避免与策略模式的耦合

drh*_*ris 5 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

drh*_*ris 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

那么,我只需要确保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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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