这个模式有没有一个名称

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#支持属性。 - Hans Passant
@HansPassant Java也是这样。 - Cubic
1
我会称之为可怕的设计气味模式。你没有使用适当的面向对象编程,而是在使用泛型进行一些hack操作。 - Euphoric
@HansPassant 如果元数据需要在运行时更改,接口是非常好的选择。特别是当元数据的一部分需要本地化时。 - Gusdor
@Euphoric 为什么不好?在某些情况下,我发现这种模式很有用,并且它对我来说是有意义的。 - BlackBear
显示剩余2条评论
1个回答

1

大家都同意这个吗?在我接受之前,我想要确认一下。我知道我正在使用作为泛型参数标准的空接口是一个标记接口,但似乎有更多的模式存在。比如使用抽象泛型基类将标记接口映射到具体类型,然后能够创建具体实现,这些实现可以接受不同类型的参数,但仍然可以通过单个公共接口调用。 - Michael
另一件事是,有时它甚至不是一个标记接口,有时你有一个带有公共字段的基本消息或上下文类,但模式的其余部分保持相同,即设置类型不可知接口,然后在其下面使用通用基础。 - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接