使用模板方法和参数化工厂方法重新设计。依赖倒置

时间:2011-06-30 15:40:40

标签: .net design-patterns

我决定使用最近获得的对设计模式的基本理解来重新设计某个子系统。

我可以看到两个抽象,因此它们已成为接口。一个遵循模板方法 IAnalyzer )模式,因为它具有针对各种场景的通用算法(仅基本操作不同),并将第二抽象(解析器)提供的数据放入数据库。另一个抽象 IParser 连接到一些外部数据源并从中恢复数据。 我还在项目中添加了参数化 Factory Method 类,该类可以创建IParser实例和IAnalyzer实例。 IAnalyzer包含对IParser的引用。 (看起来像策略给我,IAnalyzer作为一个上下文和IParser作为一个策略,但如果我错了就纠正我。)

对于IParser的每个可能实现,都有一些包含连接信息的设置对象。现在,根据文献,我们可以将参数传递给工厂模式以实例化对象。所以我正在考虑将这些设置对象用作创建IParser的工厂方法的参数。在下一步中,我使用另一个工厂方法使用先前创建的IParser实例作为参数来创建IAnalyzer对象。

(设置对象以序列化形式存储在磁盘上,并且现在不会从任何东西继承。可能它们应该吗?)基本上我使用if-else如果工厂方法中的逻辑检查传递的类型用于创建解析器的对象。每当需要创建新类型的解析器时,也需要创建相应的设置对象。因此,在工厂方法中添加新的 else if 语句将负责生成新的解析器。 (实际上有一对多的关系btwn设置对象和解析器,b / c连接信息可能包含多个地址连接到期望相同的数据源。所以工厂方法可能会返回一个解析器数组。)

基于设置对象参数的新类生成是否会违反依赖性倒置原则抽象不应该依赖于细节,而是细节应该取决于抽象),你觉得呢?

这是一些代码。

  public class DSParsersFactory
{
    public static IParser[] CreateParsers(object ConnectionInfo)
    {
        if (ConnectionInfo == null) throw new ArgumentNullException();

        List<IParser> retVal = new List<IParser>();
        if (ConnectionInfo is MDSErverSettings)
        {
            //foreach address
            MDSServerSettingsAdapter sa = new MDSServerSettingsAdapter(); //realizes IAdapterConnectionInfo
            //init sa with current address
            IParser p = CreateParser(sa);
            if (p != null) retVal.Add(p);
        }
        else if (...)

        return retVal.ToArray();
    }

    static IParser CreateParser(IAdapterConnectionInfo ia)
    {
        if (ia is MDSServerSettingsAdapter)
            return new MDSParser(ia);
        else if(...)

        return null;
    }

    public static IAnalyzer CreateAnalyzer(IParser p)
    {
        if (p == null) throw new ArgumentNullException();

        if (p is MDSParser) return new MDSAnalyzer(p);
        else if (...)

        return null;
    }
}

你是什么人?请注意,要从连接信息对象中提取多个地址,我创建了相应的适配器类,这些类将保存单个连接信息以将其传递给IParser构造函数。这很乏味但我没有想出更好的东西。 IAdapterConnectionInfo现在真的是一个空接口。我也不喜欢将System.Object类型传递给CreateParsers的想法。

感谢您的耐心等待。

P.S。主循环看起来像这样:

            var settings = Deserialize(path);

        IParser [] pArr = DSParsersFactory.CreateParsers(settings);

        foreach (IParser prs in pArr)
        {
            IAnalyzer algorithm = DSParsersFactory.CreateAnalyzer(prs);

            if (algorithm != null)
            {
                int nSuccesses = algorithm.ProcessData();

                string msg=string.Format("{0} records out of {1} were processed succussfully", nSuccesses, prs.GetDataCount());

                EventLog.WriteEntry(Settings.Default.AppName, msg);
            }
        }

1 个答案:

答案 0 :(得分:1)

我觉得很难读出你的问题,除了最后一段和其他几段,但我会尽力回答。

从我在代码中看到的,而不是使用if语句来确定IAdapterConnectionInfo对象的类型,您应该为每种类型重载方法。这将极大地提高效率和可扩展性 - 我不知道你的模式中是否可以这样做,但是如果一个新类继承自实现IAdapterConnectionInfo的旧类,并且在{ia is OldClass之前检查了ia is DerivedClass 1}}你会失去特异性。 CreateParsers方法也是如此。如果需要,调用方法可以处理问题并使用RTTI和方法,但是你的类不再依赖于那个设计,我认为这将是一件好事。

解决此问题的另一种方法是在IAdapterConnectionInfo中创建一个方法,该方法返回正确的相关ServerSettingsAdapter的类型,以及(可能存在或不存在)IServerSettingsAdapter中的另一个方法返回适当的Parser类型。然后,您可以使用反射和强制转换来加载它们。这可能会或可能不会奏效 - 我无法说出来。

很抱歉,如果我没有回答正确的问题......:P