添加功能:子类vs装饰器

时间:2009-08-25 21:13:43

标签: java design-patterns decorator subclass

我目前正在为表示层使用Oracle的ADF Faces JSF实现的遗留系统。系统依赖规则引擎使某些表单元素成为必需,禁用或甚至突出显示,具体取决于用户与它们的交互或输入的值。

在目前阶段,应用程序正在“正常工作”。处理规则引擎和前端更新的当前实现不是很优雅,并且包含大量类似于以下内容的if语句:

if(screenObj instanceof CoreInputText) {
    ((CoreInputText) screenObj).setDisabled(true);
}

为了使混合变得复杂,我们也将自己的对象混合在一起,因此整个集合不会共享一个共同的祖先,从而消除了我们执行以下操作的选项:

((CommonAncestor) screenObj).setDisabled(true);

问题在于是否值得将这部分代码重新编写为更清晰,更清晰。由于大多数屏幕元素都是ADF Faces元素,因此我们无法/允许更改其祖先以添加其他方法。

代码更改的目标有两个:清理旧代码并改进代码库,以便添加新元素或控件不会导致大量代码更改(特别是对于存在于很多地方)。

因此,如果我们继续推进这一变革,那么这将是实现我们所寻求目标的更好选择吗?对所有元素进行子类化(每次我们使用另一个预先存在的控件时需要一个新类)或实现装饰器模式?我唯一关心的是装饰器,它仍然需要为每个附加元素进行代码更改。这两个选项似乎都会减少代码更改,因为包含这些if块的多个方法不需要更新。

欢迎在子类化和装饰器之外处理此类情况的方法的任何输入!

1 个答案:

答案 0 :(得分:1)

虽然他们没有共同的祖先,但您没有指定他们是否有共同的方法。如果他们这样做,那么可能只是在运行时使用只调用该方法的代理放入一个接口,这样你就有了一个通用类型。当然,这是一种装饰器,因为它使用反射它可能太慢(尽管可能不是)但它具有任何新对象只需要实现正确的方法签名(或者可能有新对象只是实现接口,并为旧对象保留代理,并在工厂方法中有条件地创建代理,该方法检查对象是否需要它。)

此外,如果这是一个真正的setter,你可以使用apache中的BeanUtils并将其设置为一个名为disabled的属性。

编辑:鉴于它们没有相同的方法,每次添加新对象时都必须添加一些代码,除非您至少可以控制前进的新对象将具有已定义的接口。话虽这么说,如果你觉得顺着反射路线走,你可以创建一个方法类的映射(前提是这些方法都采用了布尔值 - 如果必须的话,你甚至可以强行绕过它)并查找对象在地图上。这样,当您引入新对象时,您只需在地图中添加一个条目。

然而,我的偏好是避免这种情况,因为这似乎反映得太过分了。它使得方法名称很难重构,并且IDE无法确定它们是否在该上下文中使用。我认为装饰者是乍一看的正确选择,因为在任何其他考虑的假设中,组合应该优先于继承,它将为发生的事情提供更清晰的代码路径,从长远来看改善维护。