[英]Avoiding coupling with Strategy pattern
我正在尝试将策略模式应用于特定情况,但在如何避免将每个具体策略耦合到为其提供数据的上下文 object 时遇到问题。 下面是一个模式的简化案例,它以几种不同的方式出现,但应该以类似的方式处理。
我们有一个 object 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;
}
}
现在,每个具体的策略 class 都必须与我的采集 class 耦合,这也是最有可能修改的类之一,因为它是我们应用程序的核心。 这仍然是对旧设计的改进,旧设计是Acquisition
class中的一个巨大的 switch 语句。 每种类型的数据可能有不同的转换方法(虽然Battery是简单的传递,但其他的根本不是那么简单),所以我觉得策略模式或类似的方式应该是go的方式。
我还要注意,在最终的实现中, IAnalogOutputter
将是一个抽象的 class 而不是一个接口。 这些类将位于用户可配置的列表中,并序列化为 XML 文件。 该列表必须在运行时可编辑并被记住,因此 Serializable 必须是我们最终解决方案的一部分。 万一它有所作为。
如何确保每个实现 class 都获得工作所需的数据,而不将其绑定到我最重要的类之一? 还是我以完全错误的方式处理这类问题?
Strategy Pattern
封装了一个 - 通常是复杂的 - 操作/计算。
您要返回的电压取决于
所以我会将这些放入另一个 class 并将其传递给策略实施者。
同样在序列化方面,您没有序列化策略类,可能只有它们的名称或类型名称。
好吧,您的实现似乎只需要一个采集数据。 这对于策略模式来说有点不寻常 - 但我不认为它更适合Visitor
,所以策略很好。 我将创建一个 class 作为属性,获取数据(可能从它继承)以及实现者需要的配置。
您可以做的一件事是使用工厂方法来构建您的策略。 您的个人策略只能在其构造函数中获取他们需要的个人数据元素,并且工厂方法是唯一需要知道如何在Acquisition
object 的情况下填写该数据的东西。 像这样的东西:
public class OutputterFactory
{
public static IAnalogOutputter CreateBatteryAnalogOutputter(Acquisition acq)
{
return new BatteryANalogOutputter(acq.Battery);
}
}
好的,我不想在这里给别人功劳,但我找到了一个非常适合我的目的的混合解决方案。 它完美地序列化,大大简化了新 output 类型的添加。 关键是一个接口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
进行子类化,而无需更改其中的一些外部部分。 我希望这将有助于其他一些处于类似情况的人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.