Я читал об этом «Законе Деметры», и он (и чистые классы «обертки» в целом) кажутся обычно антипаттернами. Рассмотрим класс реализации:
class FluidSimulator {
void reset() { /* ... */ }
}
Теперь рассмотрим две разные реализации другого класса:
class ScreenSpaceEffects1 {
private FluidSimulator _fluidDynamics;
public FluidSimulator getFluidSimulator() { return _fluidDynamics; }
}
class ScreenSpaceEffects2 {
private FluidSimulator _fluidDynamics;
public void resetFluidSimulation() { _fluidDynamics.reset(); }
}
И способы вызова указанных методов:
callingMethod() {
effects1.getFluidSimulator().reset(); // Version 1
effects2.resetFluidSimulation(); // Version 2
}
На первый взгляд, версия 2 кажется немного проще и следует «правилу Деметры», скрыть реализацию 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
}
В обеих версиях необходимо изменить callMethod, но в версии 2 необходимо изменить также ScreenSpaceEffects. Может ли кто-нибудь объяснить преимущество наличия оболочки/фасада (за исключением адаптеров или оболочки внешнего API или раскрытия внутреннего).
EDIT: Один из многих реальных примеров, для которых я столкнулся с этим, а не с тривиальным примером.