Я использовал этот шаблон много раз в разных местах, как правило, рядом с плагином.Есть ли название для этого рисунка
Некоторые примеры использования я использовал для систем обмена сообщениями, таких как создание подписчиков на различные типы несвязанных сообщений. Я также использовал его для общих рабочих процессов интеграции, каждый из которых нуждается в объекте контекстно-зависимой формы.
В основном шаблон состоит из определения пустого интерфейса маркера для сообщения или контекста. Затем определим интерфейс рабочего процесса высокого уровня, который работает с интерфейсом сообщения/контекста. Затем вы можете использовать фабрику, чтобы получить конкретный экземпляр рабочего процесса, и при необходимости рабочий процесс также может отвечать за разбор его сообщения/контекста из общего формата данных.
Далее вы создаете абстрактный общий базовый рабочий процесс, ответственность которого сводится только к сопоставлению вызовов методам интерфейса, которые проходят вокруг бесполезного интерфейса маркера, в вызовы абстрактных методов, которые принимают конкретную версию сообщения/контекста.
Надеюсь, это имеет смысл. Я приведу пример кода ниже. Мне бы хотелось узнать, имеет ли этот шаблон имя, потому что я заметил, что я использовал его примерно 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));
}
}
C# поддерживает атрибуты. –
@HansPassant Так делает Java. – Cubic
Я бы назвал этот ужасный дизайн запаха дизайна. Вместо того, чтобы делать правильный ООП, вы взламываете что-то дженериками. – Euphoric