2014-02-15 3 views
3

Я использовал этот шаблон много раз в разных местах, как правило, рядом с плагином.Есть ли название для этого рисунка

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

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

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

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

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

Конечный результат

public class ConcreteA : Base<MessageA> 
{ 
    public void Process(MessageA message){...} 
    public MessageA Parse(IDictionary data){...} 
} 

public class ConcreteB : Base<MessageB> 
{ 
    public void Process(MessageB message){...} 
    public MessageB Parse(IDictionary data){...} 
} 

//And both can by called by... 
public void Main(){ 
    var data = GetDataFromIntegrationSource(someContext); 
    IWorkflow impl = Factory.GetConcrete(someContext); 

    //So in your classes you're able to work with strongly typed parameters, 
    //But in the consuming code you still can use a common interface 
    //Consuming code never even knows what the strong type is. 
    IMessage msg = impl.Parse(data); 
    impl.Process(msg); 
} 

ПОЛНЫЙ ПРИМЕР

Высокоуровневые интерфейсы

public interface IGenericeMarkerInterface 
{ 
} 

public interface IGenericWorkflow 
{ 
    void Process(IGenericeMarkerInterface messageOrContext); 

    IGenericeMarkerInterface Parse(IDictionary<string, string> commonDataFormat); 
} 

Абстрактный базовый класс для картирования для конкретных методов

public abstract class GenericWorkflowBase<T> : IGenericWorkflow where T : IGenericeMarkerInterface 
{ 
    public void Process(IGenericeMarkerInterface messageOrContext) 
    { 
     Process((T)messageOrContext);  
    } 

    public IGenericeMarkerInterface Parse(IDictionary<string, string> commonDataFormat) 
    { 
     return DoParse(commonDataFormat); 
    } 

    public abstract void Process(T messageOrContext); 
    public abstract T DoParse(IDictionary<string, string> commonDataFormat); 
} 

Картирование Атрибуты

public class MappingAttributeUsedByFactoryAttribute : Attribute 
{ 
    public WorkflowType SomePropertyForMapping { get; set; } 
} 

Реализации Бетон

public class SomeRandomlyShapedMessageOrContext : IGenericeMarkerInterface 
{ 
    public int ID { get; set; } 
    public string Data { get; set; } 
} 

[MappingAttributeUsedByFactory(WorkflowType.IntegrationPartnerB)] 
public class ConcreteWorkflow : GenericWorkflowBase<SomeRandomlyShapedMessageOrContext> 
{ 
    public override void Process(SomeRandomlyShapedMessageOrContext messageOrContext) 
    { 
     //TODO: process the strongly typed message 
    } 

    public override SomeRandomlyShapedMessageOrContext DoParse(IDictionary<string, string> commonDataFormat) 
    { 
     //TODO: parse the common data into the strongly typed message    
    } 
} 

завод

public static class WorkflowFactory 
{ 
    public static IGenericWorkflow Get(WorkflowType workflow) 
    { 
     //TODO: find the concrete workflow by inspecting attributes 
    } 
} 

Пример

public static class Program 
{ 
    public static void Main(string[] args) 
    { 
     //this could be driven by a UI or some contextual data 
     var someSortOfWorkflowIdentifier = (WorkflowType)args[0]; 
     var data = GetSomeDictionaryOfData(); 

     var workflow = WorkflowFactory.Get(someSortOfWorkflowIdentifier); 

     workflow.Process(workflow.Parse(data)); 
    } 
} 
+3

C# поддерживает атрибуты. –

+0

@HansPassant Так делает Java. – Cubic

+1

Я бы назвал этот ужасный дизайн запаха дизайна. Вместо того, чтобы делать правильный ООП, вы взламываете что-то дженериками. – Euphoric

ответ

1

Да, это точно так же, как вы назвали его: Marker interface

+0

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

+0

Другое дело, что иногда его даже не интерфейс маркера, иногда у вас есть базовый Message или Context класс с общими полями, но остальная часть шаблона остается идентичной с точки зрения настройки интерфейса типа агностик, а затем общего под ним. – Michael

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