代码之家  ›  专栏  ›  技术社区  ›  Robert Fraser

包装纸/得墨忒尔定律似乎是一种反模式

  •  5
  • Robert Fraser  · 技术社区  · 14 年前

    我一直在读这个“德米特定律”的东西,它(和一般的纯“包装器”类)似乎通常是反模式的。考虑一个实现类:

    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
    }
    

    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
    }
    

    在这两个版本中,callingMethod都需要更改,但在版本2中,ScreenSpaceEffects

    其中一个真实的例子,我遇到了这个而不是一个微不足道的例子。

    3 回复  |  直到 14 年前
        1
  •  14
  •   tonio    14 年前

    主要区别在于在版本1中,作为 Bar 抽象,你无法控制 Foo 会暴露给你的客户,他们必须忍受。

    酒吧 ,您可以决定是否以及如何公开演化。这将只取决于 酒吧 抽象,而不是 的。在你的例子中,你的 抽象可能已经知道要传递哪个整数作为参数,因此您将能够让您的用户透明地使用新版本的 ,没有任何变化。

    假设现在Foo进化了,需要用户调用 foo.init() doSomething . 对于版本1,Bar的所有用户都需要看到Foo发生了变化,并修改他们的代码。仅限版本2 必须改变,它的 剂量测定 打电话 init 酒吧

        2
  •  2
  •   Matthew Flaschen    14 年前

    这显然是一个人为的例子。在许多实际情况下,callingMethod(在现实生活中,可以有多种callingMethods)可以保持幸福,不知道Foo.doSomething发生了变化,因为Bar隔离了它。例如,如果我使用一个稳定的打印API,我就不必担心我的打印机固件添加了对光泽打印的支持。我现有的黑白打印代码继续工作。我想你可以把它归为“adapter”,我认为这比你所暗示的要普遍得多。

    resetFluidSimulation(bool) resetFluidSimulation() 通过调用保持工作(不更改callingMethod) _fluidDynamics.reset(true) 在幕后。

        3
  •  2
  •   APC    14 年前

    问题是,你知道吗 callingMethod() 需要知道是否重新创建呈现表吗?

    假设某个给定的执行 调用方法() 是否需要重新创建呈现表。在这种情况下,可以使用新方法扩展包装器。然后您只需要从 .

    class ScreenSpaceEffects2 {
        private FluidSimulator _fluidDynamics;
        public void resetFluidSimulation() { _fluidDynamics.reset(false); }
        public void resetFluidSimulationWithRecreate() { _fluidDynamics.reset(true); }
    }
    

    或者,重建的决定可能完全属于其他地方。。。

    class ScreenSpaceEffects2 {
        private FluidSimulator _fluidDynamics;
        public void resetFluidSimulation() { 
                 _fluidDynamics.reset( someRuleEngine.getRecreateRenderTables() ); }
    }
    

    ... 在这种情况下 根本不需要改变。