Я бы начал с начала до конца, от вашей потребности до реализации.
Из того, что я вижу, вам необходимо получить доступ во время выполнения функции, предоставляемой интеграцией, созданной определенной системой из заданного значения. Так что ваши первые актеры бы
interface IIntegrationFeature {}
и что-то, что бы предоставить Вам эту возможность
interface IIntegratedSystem
{
T GetFeature<T>(string integrationType) where T : IIntegrationFeature;
}
клиент этой установки будет использовать актеров, как этот
IIntegratedSystem system = .... // system implementation
T feature = system.GetFeature<T>("Which integration type?");
if (feature != null)
{
//the feature exists and I'm using it
}
IIntegratedSystem
реализация языка ответственность заключается в предоставлении IIntegrationFeature
от существующего IChannelIntegration
, выбранного или созданного в режиме реального времени. Вы считали, что информируете любого клиента о том, что реализация IChannelIntegration
реализовала функцию путем реализации ISupportFeature<IIntegrationFeature>
. Что происходит, когда интеграция имеет около 20 функций? У вас будет класс, который реализует интерфейс интеграции сам по себе и еще 20 ISupports
интерфейсов. Как вы добавляете еще одну функцию? Вы модифицируете класс, добавив новый ISupports<INewFeature>
, нарушающий принцип единой ответственности. И во время компиляции вам не нужно знать, что интеграция выполняет определенную функцию, поскольку клиент может ее использовать или не использовать.В основном IChannelIntegration
больше походит на композитной интеграций, которые должны быть в состоянии дать IIntegrationFeature
и, таким образом IChannelIntegration
будет иметь определение, аналогичное IIntegratedSystem
interface IChannelIntegration
{
T GetFeature<T>() where T : IIntegrationFeature;
}
способ, как вы строите реализацию IChannelIntegration
зависит от вас, но я предпочитают создавать функции в корне вашего приложения. Mine будет таким:
class ChannelIntegration : IChannelIntegration
{
private Dictionary<Type, IIntegrationFeature> features;
public ChannelIntegration()
{
features = new Dictionary<Type, IIntegrationFeature>();
}
public void RegisterFeature<T>(IIntegrationFeature feature) where T:IIntegrationFeature
{
features.Add(typeof(T), feature);
}
public T GetFeature<T>() where T : IIntegrationFeature
{
IIntegrationFeature feature = features.TryGetValue(typeof(T), out feature) ? feature : null;
return (T)feature;
}
}
Класс ChannelIntegration
содержит список функций. Вы используете RegisterFeature
, чтобы добавить дополнительные функции, и, чтобы убедиться, что это функция, вы ограничиваете их реализацию интерфейса IIntegrationFeature
. Поэтому, когда вы добавляете новую функцию, вы не меняете класс ChannelIntegration
, вы используете его.
IIntegratedSystem
получит доступ к функции от IChannelIntegration
на основе значений времени выполнения. Это просит, как вы сказали, использовать Abstract Factory. Это будет выглядеть
interface IChannelIntegrationFactory
{
IChannelIntegration CreateIntegration(string integrationType);
}
IIntegratedSystem
будет использовать этот завод, чтобы создать IChannelIntegration
и для достижения этой цели я использовал бы механизм впрыска конструктора.
class IntegratedSystem : IIntegratedSystem
{
private IChannelIntegrationFactory integrationFactory;
public IntegratedSystem(IChannelIntegrationFactory integrationFactory)
{
this.integrationFactory = integrationFactory;
}
public T GetFeature<T>(string integrationType) where T: IIntegrationFeature
{
T integrationFeature = default(T);
IChannelIntegration integration = integrationFactory.CreateIntegration(integrationType);
if (integration != null)
{
integrationFeature = (T)integration.GetFeature<T>();
}
return integrationFeature;
}
}
IntegratedSystem
Теперь класс использует IChannelIntegrationFactory
для создания IChannelIntegration
на основе значения времени выполнения, а затем он будет извлекать из него реализованный IIntegrationFeature
, если таковые имеются.
Что нам теперь нужно реализовать этот завод, который будет создавать IChannelIntegration
с с их IIntegrationFeature
s
Пусть первым создадим новую функцию
interface ICustomFeature : IIntegrationFeature {}
class CustomFeature : ICustomFeature
{
}
и на основе этой реализации Abstract Factory, как
class ChannelIntegrationFactory : IChannelIntegrationFactory
{
public IChannelIntegration CreateIntegration(string integrationType)
{
// use integrationType to decide witch IChannelIntegration to use
IChannelIntegration integration = new ChannelIntegration();
integration.RegisterFeature<ICustomFeature>(new CustomFeature());
return integration;
}
}
Мы создали здесь ChannelIntegration
с его единственной функцией. Конечно, у вас может быть несколько путей, как вы начали, где вы создаете разные IChannelIntegrations
со своими ICustomFeature
s и извлекаете один из них на основе параметра integrationType
.
Итак, как вы это потребляете?
IIntegratedSystem system = new IntegratedSystem(new ChannelIntegrationFactory());
ICustomFeature customFeature = system.GetFeature<ICustomFeature>("Which Integration?");
if (customFeature != null)
{
//use this custom feature
}
else
{
// that's OK, will wait until is registered.
}
Вы хотите добавить новую функцию? Зарегистрируйте его в реализации абстрактной фабрики.
So would you expect to create a new abstract factory of type ChannelIntegrationFactory for each different type of ChannelIntegration?
No. Фабрика выбирает один из из списка конкретных реализаций.Вот один пример
class ChannelIntegrationFactory : IChannelIntegrationFactory
{
public IChannelIntegration CreateIntegration(string integrationType)
{
IChannelIntegration integration = null;
switch (integrationType)
{
case "MobileIntegration":
integration = new ChannelIntegration();
integration.Register<ITapGestureTrack>(new TapGestureTrack());
break;
case "DesktopIntegration":
integration = new ChannelIntegration();
integration.Register<IClickTrack>(new ClickTracker());
integration.Register<ILargeImagesProvider>(new LargeImagesProvider());
break;
}
return integration;
}
}
Вы можете даже сделать ChannelIntegration
как абстрактные и создавать специализированные объединения:
class MobileIntegration : ChannelIntegration
{
public MobileIntegration()
{
Register<ITapGestureTrack>(new TapGestureTrack());
}
}
class DesktopIntegration : ChannelIntegration
{
public DesktopIntegration()
{
Register<IClickTrack>(new ClickTracker());
Register<ILargeImagesProvider>(new LargeImagesProvider());
}
}
и абстрактная фабрика становится
class ChannelIntegrationFactory : IChannelIntegrationFactory
{
public IChannelIntegration CreateIntegration(string integrationType)
{
IChannelIntegration integration = null;
switch (integrationType)
{
case "MobileIntegration":
integration = new MobileIntegration();
break;
case "DesktopIntegration":
integration = new DesktopIntegration();
break;
}
return integration;
}
}
Просто увидеть этот класс как ваша систему загрузочный класс. Это единственный класс, который создает интеграцию с функциями. Кстати, именно так вы можете легко включить инверсию зависимостей, используя ваш предпочтительный IoC. Fiddle
Я голосующий, чтобы закрыть этот вопрос как не по теме, потому что OP просит просмотреть код. Код работает, нет конкретной проблемы для решения. – InBetween
Мои извинения, я не знал, что есть раздел обзора кода. – Eritey
@Eritey: см: [codereview.stackexchange.com] (http://codereview.stackexchange.com) – JanDotNet