Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/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
Design patterns 访问者模式和违反封装_Design Patterns - Fatal编程技术网

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