设计模式6原则之:迪米特法则

概念

迪米特法则:又叫【最少知道原则】,一个类不应该知道自己操作的类的细节,也就是说,只和朋友谈话,不和陌生人谈话

理解

  1. 一个类不应该知道自己操作的类的细节

    有这样一个场景,我们课件中有一个视频小节,现在需要更新它。更新它需要 3 个步骤:验证参数合法性,参数转化,保存到数据库

    我们可以写成下面这样:

    class Courseware {
      public function updateVideoChapter(VideoChapter chapter) {
        chaper->checkParam();
        chaper->transferParam();
        chaper->save();
      }
    }
    
    class VideoChapter {
      public function checkParam() {
        echo '校验参数';
      }
      public function transferParam() {
        echo '转换参数';
      }
      public function save() {
        echo '保存小节';
      }
    }
    

    这种情况,很明显的违反了迪米特法则,因为课件保存小节不需要知道小节保存的具体步骤,增加了代码的耦合度

    正确的做法是封装一层,只需要提供一个小节保存的方法就行,也就是隐藏操作的类的细节

    class Courseware {
      public function updateChapter(IChapter chapter) {
        chaper->update();
      }
    }
    
    interface Ichapter {
      function update();
    }
    
    class VideoChapter implements IChapter {
      public function update() {
        this->checkParam();
        this->transferParam();
        this->save();
        echo '更新视频';
      }
    
      public function checkParam() {
        echo '校验参数';
      }
      public function transferParam() {
        echo '转换参数';
      }
      public function save() {
        echo '保存小节';
      }
    }
    
  2. 只和朋友谈话,不和朋友的朋友谈话

    继续上面的更新小节的例子,假如现在需要对更新小节增加日志功能,记录谁更新了哪些字段,因此我们需要引入记录日志的方法

    class Courseware {
      public function updateChapter(IChapter chapter) {
        chaper->update();
        // 记录日志
        (new Logger())->insert();
      }
    }
    
    interface Ichapter {
      function update();
    }
    
    class VideoChapter implements IChapter {
      public function update() {
        this->checkParam();
        this->transferParam();
        this->save();
        echo '更新视频';
      }
    
      public function checkParam() {
        echo '校验参数';
      }
      public function transferParam() {
        echo '转换参数';
      }
      public function save() {
        echo '保存小节';
      }
    }
    

    你以为这样就没事了,但是还是违反了迪米特法则。

    咱们可以看下什么是课件类 Courseware 的朋友,(出现在成员变量、方法的输入输出参数中的类就是朋友),所以小节类就是课件类的朋友,日志类就不是课件类的朋友。

    这时候就需要修改成下面这样:

    class Courseware {
      public function updateChapter(IChapter chapter) {
        chaper->update();
      }
    }
    
    interface Ichapter {
      function update();
    }
    
    class VideoChapter implements IChapter {
      public Logger logger;
    
      public function __construct() {
        this->logger = new Logger();
      }
      public function update() {
        this->checkParam();
        this->transferParam();
        this->save();
        // 记录日志
        this->logger->insert();
        echo '更新视频';
      }
    
      public function checkParam() {
        echo '校验参数';
      }
      public function transferParam() {
        echo '转换参数';
      }
      public function save() {
        echo '保存小节';
      }
    }
    

    这样课件类和小节类就可以继续做好朋友了。