Java 使用Decorator模式时是否查找特定类型的Decorator?
我正在构建一个应用程序,需要使用多种类型的类似传感器。由于传感器也可能具有不同的行为或行为组合,我决定使用 简而言之,我的层次结构如下所示:Java 使用Decorator模式时是否查找特定类型的Decorator?,java,android,design-patterns,reflection,decorator,Java,Android,Design Patterns,Reflection,Decorator,我正在构建一个应用程序,需要使用多种类型的类似传感器。由于传感器也可能具有不同的行为或行为组合,我决定使用 简而言之,我的层次结构如下所示: IMeasureSensor sensor; ... CalibratedSensorDecorator s = (CalibratedSensorDecorator) findDecorator(sensor, CalibratedSensorDecorator.class); 因此,任何混凝土IsSensorDecorator类都可以装饰(包装
IMeasureSensor sensor;
...
CalibratedSensorDecorator s = (CalibratedSensorDecorator) findDecorator(sensor, CalibratedSensorDecorator.class);
因此,任何混凝土IsSensorDecorator
类都可以装饰(包装)任何混凝土IMeasureSensor
类,但由于混凝土IsSensorDecorator
也是混凝土IMeasureSensor
,它们可以彼此包装。比如说
IMeasureSensor sensor = new FilteredSensorDecorator(
new CalibratedSensorDecorator(
new AccelerometerSensor()
)
);
是声明经过过滤和校准的加速计传感器的有效语句
现在,假设我在calibredSensorDecorator
中有一个名为setCalibration()
的方法。显然我不能打电话
sensor.setCalibration();
因为IMeasureSensor
没有setCalibration()
方法。并尝试使用
((CalibratedSensorDecorator)sensor).setCalibration()
也不起作用,因为传感器
是一个过滤器传感器排序器
在这种特殊情况下,我如何访问
校准传感器装饰器
,更一般地说,如何访问任何装饰器“链”中的任何特定装饰器?我不想将它们存储为单独的变量,我想动态地存储。因为这是一个设计问题,不会有任何正确的答案,你需要选择好的还是不好的
您不应该为特定类添加方法,因为它将违反Liskov替换原则
程序中的对象应可替换为其子类型的实例,而不会改变该程序的正确性
您可以在constructorCalibredSensorDecorator
中初始化校准
,并在执行所需功能时使用它
如果这不符合您的要求,则可能校准传感器装饰器不属于您的传感器层次结构。考虑分离它并使用策略模式来决定使用哪一个。
编辑1:
我的理解是,它没有说不应该向子类型添加方法
是的,你说得对。它并不禁止添加方法,但是如果这些方法正在更改对象的状态,那么应该重新考虑。所有这些模式只是指导方针,可以根据我们的需要进行调整
解释我的理由:
假设您已经在CalibredSensorDecorator
上创建了setCalibration()
。您可以通过以下方式向内部开发人员或外部开发人员公开CalibredSensorDecorator
。您已经创建了一个工厂,它只返回IMeasureSensor
,如下所示:
public IMeasureSensor getCalibratedSensor(){
...
}
现在,API的用户只需了解这一点,并对其当前代码正常工作感到高兴。但意识到他/她错过了经过数小时调试后找到的setCalibration()
。此外,他/她还必须编写类型检查和类型转换代码来利用此功能,这对于干净的代码来说可能不是什么好事
您应该尽量使类保持不变,以便调试和维护变得轻松。重新创建对象没有什么害处,因为旧的对象将被垃圾收集
再次,这只是我的建议,它是你慎重考虑什么对你的用例最好的决定。如果该方法是强制性的,您仍然可以继续使用新方法来创建该方法,并确保已制作了适当的文档,以使用户了解其用法。而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;
}
方法ISensorDecorator.getDecoratee()
只返回“decoratee”,即decorator修饰的IMeasureSensor
public IMeasureSensor getDecoratee(){
return mMeasureSensor;
}
然后可以使用findDecorator()
查找给定类型的(最外层)装饰器,如下所示:
IMeasureSensor sensor;
...
CalibratedSensorDecorator s = (CalibratedSensorDecorator) findDecorator(sensor, CalibratedSensorDecorator.class);
我不是Liskov替换原则方面的专家,但从我的理解来看,这并不是说不应该向子类型添加方法?如果是这样的话,继承的作用不是很有限吗?实际上,我正按照您的建议进行操作,在构造函数中使用校准
参数。但我希望能够更改校准和其他参数,而不必为了更改变量而重新创建新对象……谢谢,我明白你的意思。如果我使用策略模式,我将如何“链接”但是,将任意数量的策略组合在一起?策略可以是将传感器分为两类:一类不需要校准,另一类需要校准。假设IMeasureSensor
是一个没有calibration的
和IMeasureSensorWithCalibration
另一个,让API的用户决定他/她更喜欢哪一个。您还可以在IMeasureSensorWithCalibration
中扩展IMeasureSensor
,以指示接口隔离。