Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Decorator模式时是否查找特定类型的Decorator?_Java_Android_Design Patterns_Reflection_Decorator - Fatal编程技术网

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替换原则

程序中的对象应可替换为其子类型的实例,而不会改变该程序的正确性

您可以在constructor
CalibredSensorDecorator
中初始化
校准
,并在执行所需功能时使用它

如果这不符合您的要求,则可能
校准传感器装饰器
不属于您的传感器层次结构。考虑分离它并使用策略模式来决定使用哪一个。
编辑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
,以指示接口隔离。