避免与策略模式的耦合

时间:2011-05-04 22:19:06

标签: c# oop design-patterns strategy-pattern decoupling

我正在尝试将策略模式应用于特定情况,但是我遇到了如何避免将每个具体策略与为其提供数据的上下文对象耦合的问题。以下是模式的简化情况,它以几种不同的方式出现,但应以类似的方式处理。

我们有一个对象Acquisition,它提供与特定时间段相关的数据 - 基本上是使用不同硬件收集的一堆外部数据。它已经太大了,因为它包含了大量的数据,所以我不想给它任何进一步的责任。我们现在需要获取一些这些数据,并根据一些配置向一块硬件发送相应的电压。

因此,想象下面的(简化得很多)类:

class Acquisition
{
    public Int32 IntegrationTime { get; set; }
    public Double Battery { get; set; }
    public Double Signal { get; set; }
}

interface IAnalogOutputter
{
    double getVoltage(Acquisition acq);
}

class BatteryAnalogOutputter : IAnalogOutputter
{
    double getVoltage(Acquisition acq)
    {
        return acq.Battery;
    }
}

现在,每个具体的策略类都必须耦合到我的Acquisition类,它也是最有可能被修改的类之一,因为它是我们应用程序的核心。这仍然是对旧设计的改进,旧设计是Acquisition类中的一个巨大的开关语句。每种类型的数据都可能有不同的转换方法(虽然电池是一种简单的传递方式,而其他类型的传输方式并不那么简单),所以我觉得应该采用策略模式或类似的方式。

我还要注意,在最终实现中,IAnalogOutputter将是一个抽象类而不是接口。这些类将位于可由用户配置并序列化为XML文件的列表中。该列表必须在运行时可编辑并记住,因此Serializable必须是我们最终解决方案的一部分。如果它有所作为。

如何确保每个实现类获取所需的数据,而不必将其绑定到我最重要的类之一?或者我是以完全错误的方式处理这类问题?

3 个答案:

答案 0 :(得分:2)

Strategy Pattern封装了一个 - 通常是复杂的 - 操作/计算。

您想要返回的电压取决于

  • 配置
  • 一些采集数据

所以我会把它们放到另一个类中并将它传递给策略实现者。

同样在序列化方面,您没有序列化策略类,也许只有它们的名称或类型名称。


更新

好吧,您的实现似乎只需要一个采集数据。对于策略模式来说这有点不寻常 - 但我不相信它更适合Visitor因此策略很好。除了实现者需要的配置之外,我还会创建一个具有属性,获取数据(可能从它继承)的类。

答案 1 :(得分:0)

您可以做的一件事是使用工厂方法来构建您的策略。您的个人策略只能在构造函数中获取所需的各个数据元素,而工厂方法是唯一需要知道如何在给定Acquisition对象的情况下填充数据的方法。像这样:

public class OutputterFactory
{
    public static IAnalogOutputter CreateBatteryAnalogOutputter(Acquisition acq)
    {
        return new BatteryANalogOutputter(acq.Battery);
    }



}

答案 2 :(得分:0)

好的,我不想在这里给别人这个功劳,但我找到了一个适合我目的的混合解决方案。它完美地序列化,并大大简化了新输出类型的添加。关键是单个界面IOutputValueProvider。还要注意这个模式如何轻松地处理检索不同的数据存储方式(例如字典而不是参数)。

interface IOutputValueProvider
{
    Double GetBattery();
    Double GetSignal();
    Int32 GetIntegrationTime();
    Double GetDictionaryValue(String key);
}

interface IAnalogOutputter
{
    double getVoltage(IOutputValueProvider provider);
}

class BatteryAnalogOutputter : IAnalogOutputter
{
    double getVoltage(IOutputValueProvider provider)
    {
        return provider.GetBattery();
    }
}

class DictionaryValueOutputter : IAnalogOutputter
{
    public String DictionaryKey { get; set; }
    public double getVoltage(IOutputValueProvider provider)
    {
        return provider.GetDictionaryValue(DictionaryKey);
    }
}

那么,我只需要确保Acquisition实现接口:

class Acquisition : IOutputValueProvider
{
    public Int32 IntegrationTime { get; set; }
    public Double Battery { get; set; }
    public Double Signal { get; set; }
    public Dictionary<String, Double> DictionaryValues;

    public double GetBattery() { return Battery;}
    public double GetSignal() { return Signal; }
    public int GetIntegrationTime() { return IntegrationTime; }
    public double GetDictionaryValue(String key) 
    {
        Double d = 0.0;
        return DictionaryValues.TryGetValue(key, out d) ? d : 0.0;
    }
}

这不是完美的,因为现在必须维护一个巨大的界面,并且在Acquisition中有一些重复的代码,但是对于我应用程序的其他部分而言,更改某些内容的风险要小得多。它还允许我开始子类化Acquisition而无需更改其中的一些外部部分。我希望这会对类似情况下的其他人有所帮助。