我正在构建一个需要使用多种类似传感器的应用。由于传感器也可能有不同的行为或行为组合,我决定使用decorator pattern。
简而言之,我的层次结构如下:
因此,任何具体的ISensorDecorator
类都可以装饰(包装)任何具体的IMeasureSensor
类,但由于具体的ISensorDecorator
也是具体的IMeasureSensor
,所以可以互相包裹。例如,
IMeasureSensor sensor = new FilteredSensorDecorator(
new CalibratedSensorDecorator(
new AccelerometerSensor()
)
);
是一个有效的声明,声明了经过滤波和校准的加速计传感器。
现在让我们说setCalibration()
中有一个名为CalibratedSensorDecorator
的方法。显然我无法打电话
sensor.setCalibration();
因为IMeasureSensor
没有setCalibration()
方法。并尝试使用
((CalibratedSensorDecorator)sensor).setCalibration()
由于sensor
是FilteredSensorDecorator
,也不会工作。
如何在这种特殊情况下进入CalibratedSensorDecorator
,更常见的是在任何"链中的任何特定装饰者"装饰者?我不想将它们存储为单独的变量,我想动态地将它们存储起来。
答案 0 :(得分:1)
由于它是一个设计问题,所以没有任何正确的答案,你需要做出好的或不好的选择。
您不应该为特定类添加方法,因为它会违反Liskov substitution principle
程序中的对象应该可以替换其子类型的实例,而不会改变该程序的正确性。
您可以在构造函数calibration
中初始化CalibratedSensorDecorator
并在执行所需函数时使用它。
如果这不符合您的要求,则CalibratedSensorDecorator
可能不属于您的传感器层次结构。考虑将其分开并使用策略模式来决定使用哪一个。
我的理解并不是说你不应该为子类型添加方法?
是的,你是对的。它不禁止添加方法,但如果方法正在改变Object的状态,那么应该重新考虑它。所有这些模式都只是可以根据我们的需求进行调整的指南。
解释我的理由:
想象一下,您已在setCalibration()
上创建了CalibratedSensorDecorator
。您可以通过以下方式向内部开发人员或外部开发人员公开CalibratedSensorDecorator
。您创建了一个只返回IMeasureSensor
的工厂,如下所示:
public IMeasureSensor getCalibratedSensor(){
...
}
现在,您的API用户只是得到了这个,并且很高兴他/她的当前代码正常运行。但是意识到他/她错过了经过数小时调试后发现的setCalibration()
。此外,他/她必须编写类型检查和类型转换代码以使用此功能,这可能不适合干净的代码。
您应该尽量使您的类保持不变,以便调试和维护变得轻松。重新创建对象没有坏处,因为旧的将被垃圾收集。
再一次只是我的建议,你决定仔细考虑什么是最适合你的用例。如果必须使用新的方法来创建方法,您仍然可以继续,并确保已经制作了适当的文档以使用户了解其用法。
答案 1 :(得分:0)
虽然Sagar的回答讨论了考虑使用另一种方法而不是装饰器模式的一些(有效)原因,但我想出了一个解决找到正确装饰器的实际问题的工作解决方案。
=
方法/**
* Walks the decorator hierarchy recursively from the outside in (excluding the final
* IMeasureSensor which is not a ISensorDecorator), and returns the decorator of the given class.
* If none can be found, null is returned.
*/
IMeasureSensor findDecorator(IMeasureSensor sensor, Class decoratorClass){
if( ISensorDecorator.class.isAssignableFrom(sensor.getClass()) ){
return (sensor.getClass() == decoratorClass)
? sensor
: findDecorator(((ISensorDecorator) sensor).getDecoratee(), decoratorClass);
}
else
return null;
}
只返回“decoratee”,即装饰器装饰的ISensorDecorator.getDecoratee()
。
IMeasureSensor
然后,您可以使用public IMeasureSensor getDecoratee(){
return mMeasureSensor;
}
找到给定类型的(最外层)装饰器,如下所示:
findDecorator()