Design patterns 访问者模式和违反封装
在这里,我们将一个对象传递给一个向其添加操作的函数。在这里,它违反了封装。它是好的面向对象设计吗?我不认为这违反了封装,因为Design patterns 访问者模式和违反封装,design-patterns,Design Patterns,在这里,我们将一个对象传递给一个向其添加操作的函数。在这里,它违反了封装。它是好的面向对象设计吗?我不认为这违反了封装,因为访问者不知道所访问对象的内部结构 在您的汽车示例中,我们的汽车对象知道它有4个车轮和一个汽油发动机,但访问者只知道我们告诉它什么,而不知道我们如何存储数据: void accept(CarElementVisitor *visitor) { visitor->visit(this); } } 稍后,我们可以在不更改访问者的访问调用的情况下更改
访问者不知道所访问对象的内部结构
在您的汽车示例中,我们的汽车对象知道它有4个车轮和一个汽油发动机,但访问者只知道我们告诉它什么,而不知道我们如何存储数据:
void accept(CarElementVisitor *visitor) {
visitor->visit(this);
}
}
稍后,我们可以在不更改访问者的访问调用的情况下更改Car对象的实现:
void accept(CarElementVisitor *visitor) {
visitor->visit(wheel_1);
visitor->visit(wheel_2);
visitor->visit(wheel_3);
visitor->visit(wheel_4);
visitor->visit(gasEngine);
}
如果通过计算对象内部发生变化时可能直接受到影响的函数的数量来度量封装,那么在实现Element::accept(Visitor)
接口时,模式将ConcreteElement
的封装减少至少1。如果需要扩展ConcreteElement
的接口以提供操作来实现ConcreteVisitor
的功能,则封装可能会进一步减少
模式本身既不是好的,也不是坏的,因为通常是环境导致模式是有利的或是不利的。因此,设计师应该考虑模式的意图、动机、适用性和后果。访问者模式的目的是允许定义新的操作,而不改变操作所基于的类。虽然不能保证,但与向元素
本身添加操作相比,它可能会增加元素
系列的相对封装
例如,考虑一个操作要检查<代码> Currase< /Cord>对象的流体级别的情况。在没有访问者的情况下,
CarElement
界面声明了一个check\u fluid\u levels()
函数:
void accept(CarElementVisitor *visitor) {
//wheels now stored in array
visitor->visit(wheels[0]);
visitor->visit(wheels[1]);
visitor->visit(wheels[2]);
visitor->visit(wheels[3]);
visitor->visit(gasEngine);
}
虽然检查某些CarElement
的液位可能有意义,如Break
和windshieldwirer
,但可能对所有CarElement
对象(如车轮
)没有意义。然而,由于在CarElement
界面上声明了check\u fluid\u levels()
另一方面,如果使用访客模式,则只有检查液位有意义的元素才会提供check\u fluid\u levels()
功能
CarElement { check_fluid_levels() }
Break: CarElement { check_fluid_levels() }
WindshieldWiper: CarElement { check_fluid_levels() }
Wheel: CarElement { check_fluid_levels() }
for e in car:
e.check_fluid_levels()
当accept()
函数的相对封装减少1时,相对封装的伸缩性比将操作添加到CarElement
要好。考虑添加一个新的操作来检查<代码> CARESTION< /代码>的排放水平。在这种情况下,上述CarElement
s都不会提供有意义的check_emissions()
功能。对于访问者,新操作不可能达到封装级别;另一方面,如果将操作添加到CarElement
,则封装级别会发生变化
下面是一个图表,列出了使用上述示例和两个操作(检查液位和检查排放)访问元件的内部的功能计数:
卡莱伦来访者
操作
突破2
挡风玻璃雨刮器2
轮子2 1我觉得这里应该问:这是如何违反封装的?封装并不意味着“在一个类中尽可能地填满所有东西,即使你不需要”。我建议你读斯科特·迈尔斯的《圣经》。
CarElement { accept(Visitor) }
Break: CarElement { accept(Visitor); check_fluid_levels() }
WindshieldWiper: CarElement { accept(Visitor); check_fluid_levels() }
Wheel: CarElement { accept(Visitor) }
FluidChecker: Visitor { ... }
FluidChecker checker
for e in car:
e.accept(checker)
CarElement Visitor
operations operations
Break 2 2
WindshieldWiper 2 2
Wheel 2 1