Rob*_*ser 5 oop design-patterns anti-patterns law-of-demeter
我一直在阅读这个"德米特定律"的东西,它(和一般的纯粹的"包装"类)似乎通常都是反模式.考虑一个实现类:
class FluidSimulator {
void reset() { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
现在考虑另一个类的两种不同实现:
class ScreenSpaceEffects1 {
private FluidSimulator _fluidDynamics;
public FluidSimulator getFluidSimulator() { return _fluidDynamics; }
}
class ScreenSpaceEffects2 {
private FluidSimulator _fluidDynamics;
public void resetFluidSimulation() { _fluidDynamics.reset(); }
}
Run Code Online (Sandbox Code Playgroud)
以及调用所述方法的方法:
callingMethod() {
effects1.getFluidSimulator().reset(); // Version 1
effects2.resetFluidSimulation(); // Version 2
}
Run Code Online (Sandbox Code Playgroud)
乍一看,版本2看起来有点简单,遵循"Demeter规则",隐藏Foo的实现等等.但这会将FluidSimulator中的任何更改与ScreenSpaceEffects联系起来.例如,如果添加一个参数来重置,那么我们有:
class FluidSimulator {
void reset(bool recreateRenderTargets) { /* ... */ }
}
class ScreenSpaceEffects1 {
private FluidSimulator _fluidDynamics;
public FluidSimulator getFluidSimulator() { return _fluidDynamics; }
}
class ScreenSpaceEffects2 {
private FluidSimulator _fluidDynamics;
public void resetFluidSimulation(bool recreateRenderTargets) { _fluidDynamics.reset(recreateRenderTargets); }
}
callingMethod() {
effects1.getFluidSimulator().reset(false); // Version 1
effects2.resetFluidSimulation(false); // Version 2
}
Run Code Online (Sandbox Code Playgroud)
在这两个版本中,需要更改callingMethod,但在版本2中,还需要更改ScreenSpaceEffects .有人可以解释具有包装器/外观的优势(除了适配器或包装外部API或暴露内部API).
编辑:我遇到的许多真实例子之一,而不是一个简单的例子.
ton*_*nio 14
主要区别在于,在版本1中,作为Bar抽象的提供者,您无法控制如何Foo暴露.任何改变Foo都将暴露给您的客户,他们将不得不忍受它.
对于版本2,作为抽象提供者Bar,您可以决定是否以及如何公开变换.它只取决于Bar抽象,而不是抽象Foo.在您的示例中,您的Bar抽象可能已经知道要传递哪个整数作为参数,因此您将能够让您的用户透明地使用新版本Foo,而根本不做任何更改.
假设现在Foo发展,并要求用户foo.init()在任何调用之前调用doSomething.对于版本1,Bar的所有用户都需要看到Foo已更改,并调整其代码.对于版本2,只Bar需要更改,如果需要则doSomething调用它init.这导致更少的错误(只有抽象的作者Bar必须知道并理解抽象Foo和类之间的较少耦合.