2011-05-04 108 views
5

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

我们有一个对象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类。每种类型的数据可能有不同的转换方法(虽然Battery是一个简单的转接,其他转换方式并不那么简单),所以我觉得战略模式或类似的应该是一条路。

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

我该如何确保每个实现类都能获得所需的数据,而无需将它绑定到我最重要的类之一上?还是我以完全错误的方式处理这类问题?

回答

0

好吧,我讨厌这里不是给别人的功劳,但我发现效果非常好,我的目的的混合解决方案。它完美的序列化,并大大简化了新的输出类型的添加。关键是一个界面,IOutputValueProvider。还要注意这种模式如何轻松处理检索存储数据的各种方法(如Dictionary而不是参数)。

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而不必更改这些外部件。我希望这会在类似的情况下帮助其他人。

2

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

要返回的电压取决于

  • 件配置
  • 采集数据的一些

所以我把这些到另一个类,并把它传递给战略实施者。

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


UPDATE

嗯,看来你实现只需要一块采集数据。这对于一种战略模式来说有点不寻常 - 但我不认为它更适合Visitor,所以策略是好的。除了实现者需要的配置之外,我还将创建一个具有属性,采集数据(可能从中继承)的类。

+0

澄清 - 采集数据包含约20条信息,所有这些信息将被各种电压输出器使用。每个实现只使用一个数据段,但是电压输出器的不同可能实现方式会有相同数量(20个)。那么,我如何从'Acquisition'获取到'另一个类将它传递给策略实现者?'?不过,关于序列化的好处,我肯定会考虑。 – drharris 2011-05-04 22:33:00

0

你可以做的一件事就是使用工厂方法来构建你的策略。您的个人策略可以将其构造函数仅存入其所需的单个数据元素,而工厂方法是唯一需要知道如何填充该数据的对象。事情是这样的:

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



} 
+0

我曾经想过,但是对于每一个新的数据来说,我必须添加一个属性,一个方法和一个类。虽然它将它分离得更多一些,但它使得残余量增加了3倍。但是,我现在想知道是否为此使用单独的方法将是最佳选择。 – drharris 2011-05-04 23:04:26