1

我有一个类层次结构,负责将一个模型(或消息)解析或映射到另一个。它具有非平凡的逻辑。

internal interface IMessageParser<T, K>
    where T : class
    where K : class
{
    K Serialize(T originalMessage);
    T Deserialize(K concreteMessage);
}

internal abstract class OriginalToConcreteMessageParser : IMessageParser<OriginalMessage, ConcreteMessage>
{
    // some private methods that do stuff and are called in the Serialize() method

    public virtual ConcreteMessage Serialize(OriginalMessage originalMessage)
    {
        // some stuff
    }
}

这些具体的解析器有 21 个:

internal sealed class OriginalToConcreteMessageParserFooMessageParser : OriginalToConcreteMessageParser 
{
}

internal sealed class OriginalToConcreteMessageParserBarMessageParser : OriginalToConcreteMessageParser 
{
}

我想添加一个新的私有方法OriginalToConcreteMessageParser并在Serialize(). 让我们调用这个方法Baz()

我可以创建OriginalToConcreteBazMessageParser并使所有 21 个具体实现都继承自此,但我不希望这样做。

提供的功能Baz()绝对是在OriginalToConcreteMessageParser.

总之,我想注入一个方法并在不接触的情况下OriginalToConcreteMessageParser调用它。Serialize()OriginalToConcreteMessageParser

4

2 回答 2

4

我认为你可以尝试一些装饰模式的实现,或者策略模式。

装饰者有这个动机,或多或少与你所拥有的相同:

例如,考虑窗口系统中的窗口。为了允许滚动窗口的内容,我们可能希望在适当的时候添加水平或垂直滚动​​条。假设窗口由 Window 类的实例表示,并假设该类没有添加滚动条的功能。我们可以创建一个子类 ScrollingWindow 来提供它们,或者我们可以创建一个 ScrollingWindowDecorator 来将此功能添加到现有的 Window 对象。在这一点上,任何一种解决方案都可以。现在让我们假设我们也希望能够为我们的窗口添加边框。同样,我们原来的 Window 类没有支持。ScrollingWindow 子类现在提出了一个问题,因为它有效地创建了一种新的窗口。如果我们希望为所有窗口添加边框支持,我们必须创建子类 WindowWithBorder 和 ScrollingWindowWithBorder。显然,这个问题随着每一个新特性的添加而变得更糟。对于装饰器解决方案,我们只需创建一个新的 BorderedWindowDecorator——在运行时,我们可以使用 ScrollingWindowDecorator 或 BorderedWindowDecorator 或两者来装饰现有的窗口,只要我们认为合适。

但可能它比战略更难实施,而且可能对你实际需要的东西来说太强大了。当子类将合并一个、两个或多个类的功能时,装饰器很好,但如果只有一个类,则使用精确的接口。

使用 strategy,您可以轻松切换类的特定行为。当唯一认为更改是一个函数并且行为通常不是组合的,而只是在不同的实现之间有所不同时,这是很好的。假设所有的类都有一个共同的行为,但是在序列化的那一刻,它们可以执行一些稍微不同的操作。如何处理?好吧,您使您的 IMessageParser 能够接收解析策略(实现 interfaz 的对象可能只是一个函数,因此您考虑放入 BAZ() 的所有代码都将在策略对象中)。在每个具体类中,如果存在策略,则序列化函数会使用它。如果策略为空,具体类只使用默认行为。

这很好,因为知道,您想使用该Baz()函数向您的序列化函数添加一些功能,但仅在某些情况下,这可以解决问题。而且,在未来,它还允许您在序列化期间添加一些进一步的行为来执行,只需创建新的策略对象。

我会使用策略。你创建一个SerializeStrategy接口,一个execute方法。然后是一个或多个实现该接口的具体类。然后在接口中定义一个setStrategy方法IMessageParser,并在基类OriginalToConcreteMessageParser或该级别的任何其他类中实现它,并将策略对象保存在那里。在子类中,只需检查是否有要使用的策略。

如果您仔细阅读该模式,并且尽可能地让所有参与者解耦,您就可以构建一个 SOLID 模型,并且易于维护应用程序。

正如我们可以在上面的同一链接中看到的那样:

这允许在行为和使用该行为的类之间更好地解耦。可以在不破坏使用它的类的情况下更改行为,并且类可以通过更改使用的特定实现在行为之间切换,而无需任何重大的代码更改。行为也可以在运行时和设计时更改。例如,一个汽车对象的刹车行为可以从 BrakeWithABS() 更改为 Brake(),方法是将刹车行为成员更改为:brakeBehavior = new Brake(); 这为设计提供了更大的灵活性,并且与开/关原则 (OCP) 相一致

于 2014-01-31T09:29:30.470 回答
0

您可以为此使用委托,但显然您必须更改方法签名:

internal abstract class OriginalToConcreteMessageParser : IMessageParser<OriginalMessage, ConcreteMessage>
{
    public virtual ConcreteMessage Serialize(OriginalMessage originalMessage, Func<OriginalMessage, ConcreteMessage> baz)
    {
        return baz(originalMessage);
    }
}

您可以选择将重载添加到注入该方法Serialize的具体类中:Baz

OriginalToConcreteMessageParserFooMessageParser

internal sealed class OriginalToConcreteMessageParserFooMessageParser : OriginalToConcreteMessageParser
{
    public ConcreteMessage Serialize(OriginalMessage originalMessage)
    {
        Func<OriginalMessage, ConcreteMessage> baz = message =>
            {
                ConcreteMessage foo = ToFoo(message);

                return foo;
            };

        return base.Serialize(originalMessage, baz);
    }
}

OriginalToConcreteMessageParserBarMessageParser

internal sealed class OriginalToConcreteMessageParserBarMessageParser : OriginalToConcreteMessageParser
{
    public ConcreteMessage Serialize(OriginalMessage originalMessage)
    {
        Func<OriginalMessage, ConcreteMessage> baz = message =>
        {
            ConcreteMessage bar = ToBar(message);

            return bar;
        };

        return base.Serialize(originalMessage, baz);
    }
}
于 2014-01-31T10:03:36.047 回答