java - 使用装饰器模式时找到特定类型的装饰器?
问题描述
我正在构建一个需要使用多种类似传感器的应用程序。由于传感器也可能具有不同的行为或行为组合,因此我决定使用装饰器模式。
简而言之,我的层次结构如下所示:
因此,任何具体ISensorDecorator
类都可以装饰(包装)任何具体IMeasureSensor
类,但由于具体 ISensorDecorator
也是具体的IMeasureSensor
,它们可以相互包装。所以例如
IMeasureSensor sensor = new FilteredSensorDecorator(
new CalibratedSensorDecorator(
new AccelerometerSensor()
)
);
是声明经过过滤和校准的加速度计传感器的有效语句。
现在假设我有一个名为setCalibration()
in的方法CalibratedSensorDecorator
。显然我不能打电话
sensor.setCalibration();
因为IMeasureSensor
没有setCalibration()
方法。并尝试使用
((CalibratedSensorDecorator)sensor).setCalibration()
也不行,因为sensor
是FilteredSensorDecorator
.
在这种特殊情况下,更一般地说,我怎样才能到达CalibratedSensorDecorator
任何装饰器“链”中的任何特定装饰器?我不想将它们存储为单独的变量,我想动态地进行。
解决方案
由于它是一个设计问题,因此不会有任何正确答案,您需要做出选择,可能好或不好。
您不应该为特定类添加方法,因为它会违反Liskov substitution principle
程序中的对象应该可以用其子类型的实例替换,而不会改变该程序的正确性。
您可以初始化calibration
in 构造函数CalibratedSensorDecorator
并在执行所需函数时使用它。
如果这不符合您的要求,则可能CalibratedSensorDecorator
不属于您的传感器层次结构。考虑将其分离并使用策略模式来决定使用哪一个。
编辑1:
我的理解并不是说您不应该向子类型添加方法?
是的你是对的。它不禁止添加方法,但如果方法正在更改对象的状态,则应重新考虑。所有这些模式只是可以根据我们的需要进行调整的指导方针。
解释我的理由:
想象一下,您已经创建了setCalibration()
on CalibratedSensorDecorator
。您可以通过以下方式向CalibratedSensorDecorator
内部开发人员或外部开发人员公开。您创建了一个工厂,它只返回IMeasureSensor
如下:
public IMeasureSensor getCalibratedSensor(){
...
}
现在,您的 API 用户只需了解这一点,并且很高兴他/她当前的代码正在运行。但意识到他/她错过了setCalibration()
几个小时的调试后发现的。此外,他/她必须编写类型检查和类型转换代码才能使用此功能,这对于干净的代码可能不是很好。
你应该尽量保持你的类是不可变的,以便调试和维护方便。重新创建对象没有害处,因为旧对象将被垃圾收集。
这只是我的建议,您决定仔细考虑什么最适合您的用例。如果它是强制性的,您仍然可以继续使用您的新方法来创建该方法,并确保已制作适当的文档以使用户了解其用法。