2009-04-06 2 views
0

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

Так, например, мы имеем:

 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{} 

Это позволяет 3-й стороны, чтобы определить свою позицию в цепочке.

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

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

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

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

Может быть, я должен просто сохранить список для основных поставщиков и добавить до/после attribs для сторонних поставщиков ...

ответ

1

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

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

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

class ProviderList : List<IMetadataProvider { } 

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

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

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

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

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

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

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

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

+0

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

Смежные вопросы