Лучший способ аннотирования цепочек поставщиков

StackOverflow https://stackoverflow.com/questions/723665

  •  05-09-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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

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

class ProviderList : List<IMetadataProvider { }

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top