Лучший способ аннотировать цепочки поставщиков - PullRequest
0 голосов
/ 07 апреля 2009

Media Browser имеет модель провайдера, это в основном цепочка классов, которые вызываются в определенном порядке для каждой сущности.

Так, например, у нас есть:

        providers = new List<IMetadataProvider>();
        providers.Add(new ImageFromMediaLocationProvider());
        providers.Add(new ImageByNameProvider());
        providers.Add(new MovieProviderFromXml());
        providers.Add(new MovieDbProvider());
        providers.Add(new TVProviderFromXmlFiles());
        providers.Add(new TvDbProvider());
        providers.Add(new VirtualFolderProvider());
        providers.Add(new FrameGrabProvider());
        providers.Add(new MediaInfoProvider());

Порядок поставщиков в списке значительный поставщики более высокого порядка имеют приоритет над поставщиками более низкого порядка.

Недавно я попытался сделать эту часть расширяемой. Таким образом, сторонняя DLL может определить своих собственных провайдеров, которые будут внедрены в нашу цепочку.

Проблема в том, что как только вы позволяете третьим сторонам вводить себя в цепочку, вы теряете центральное место для определения этого порядка.

Мое текущее решение, с которым мне немного не по себе, - это определить необязательный атрибут приоритета для каждого поставщика, а затем упорядочить по приоритету.

Так, например, теперь у меня есть:

[ProviderPriority(20)]
class ImageByNameProvider{}

Это позволяет сторонним организациям определять свою позицию в цепочке.

Другие решения, о которых я думал, были до и после атрибута, например,

[Before(typeof(ImageByNameProvider))]
class ImageFromMediaLocationProvider {} 

Но я не уверен, проще ли это или сложнее программировать.

Есть ли другие варианты решения этой проблемы? Какое решение вы бы выбрали?

Возможно, мне следует просто сохранить список основных поставщиков и добавить атрибуты До / После для сторонних поставщиков ...

1 Ответ

1 голос
/ 07 апреля 2009

Кажется, что на самом деле здесь есть несколько разных проблем, которые нужно решить. Основная проблема заключается в попытке создать механизм, позволяющий вставить произвольный объект в существующий список в некоторой точке в середине этого списка.

Вы не описываете, как на самом деле выглядит интерфейс IMetadataProvider, но у него должен быть какой-то способ уникальной идентификации провайдера (лучший вариант - использовать Guid). Преимущество по сравнению с использованием имени класса заключается в том, что оно позволяет вам переименовывать классы по мере необходимости во время рефакторинга и т. Д., Не затрагивая пользовательских (сторонних) поставщиков, если вы сохраняете Guid прежним.

Вместо того, чтобы использовать простой список, вы, вероятно, должны получить свой собственный список:

class ProviderList : List<IMetadataProvider { }

, который предоставляет возможность для собственного (стороннего) поставщика установить / удалить себя из этого списка. Эти механизмы должны быть достаточно умными, чтобы знать, как вставить нового провайдера в середину цепочки, и достаточно умными, чтобы знать, как обрабатывать несколько пользовательских провайдеров, которые были вставлены. Точно так же процесс удаления должен быть продуманным, чтобы справляться с подобными проблемами, а также гарантировать, что кто-то не попытается удалить одного из ваших «основных» провайдеров.

Хорошим подходом здесь, вероятно, будет передача Guid провайдера, после которого вы хотите вставить его, в качестве параметра метода Install (). Метод Remove () также использует Guid провайдера для удаления.

Например, допустим, я вставляю нового поставщика после MovieProviderFromXml. Затем другой сторонний поставщик также устанавливает нового поставщика после MovieProviderFromXml. Каким должен быть новый порядок цепочек? Всегда ли второй провайдер вставляет сразу после MovieProviderFromXml или запускает его там, а затем пропускает мимо любых пользовательских провайдеров и вставляет после последнего установленного нестандартного провайдера (то есть перед следующим «основным» провайдером?

С этим вопросом связана идея о том, что у вас должен быть какой-то способ различать ваших «основных» провайдеров и нестандартных провайдеров.

Наконец, вам нужно убедиться, что есть способ обработки сбоев в цепочке, особенно когда пользовательский провайдер вставлен в неправильное место.

Вы хотите всегда поддерживать базовый ("основной") список цепочки по умолчанию. Когда новый поставщик установлен в середине этой цепочки, новая цепочка должна быть создана, но вы не хотите терять базовую цепочку. Это дает вам возможность вернуть цепь в состояние по умолчанию.

Цепочка, основанная на приоритете, является проблематичной, поскольку вам необходимо определить, как обрабатывать приоритетные коллизии. Что касается набора атрибутов До / После, разрешите ли вы оба на одном и том же провайдере? Вероятно, нет, поэтому может иметь смысл создать атрибут ProviderChainAttribute со свойством перечисления ChainInsert, где ChainInsert определяет значения перечисления «До» и «После». Это позволяет принудить пользовательского поставщика принять решение о том, устанавливать ли он до или после указанного поставщика. Я бы все равно использовал Guid, а не тип.

Надеюсь, это даст вам другие идеи о том, как подойти к этой проблеме.

...