单一职责原则:一个模块的功能只能因为一个原因进行修改。

单一职责介绍

我们假设一个场景:

有一个动物类,它会呼吸空气,用一个类描述动物呼吸这个场景:

class Animal{  
    public function breathe(string $animal){  
        echo $animal . "呼吸空气";  
    }  
}  

$animal = new Animal();  
$animal->breathe("牛");  
$animal->breathe("羊");  
$animal->breathe("猪");  

当有一天我们发现并不是所有的动物都呼吸空气,例如水生的动物他们呼吸的是水,我们就需要进行如下的代码改动。

class Animal{  
    public function breathe(string $animal,string $type){  
        if ($type == "terrestrial") {
            echo $animal . "呼吸空气";  
        } else {
            echo $animal . "呼吸水";  
        }

    }  
}  

$animal = new Animal();  
$animal->breathe("牛","terrestrial");  
$animal->breathe("羊","terrestrial");  
$animal->breathe("猪","terrestrial");  
$animal->breathe("鱼","aquatic");

上述代码的改动就违反了单一原则,breathe 方法会因为两个因素造成修改,分别是 terrestrial 和 aquatic 。

这种违反会带来什么问题,最直观的问题就是会更容易造成 bug, 比如我们 terrestrial 需要增加新的功能,在些新功能的时候引入了一些 bug ,这将导致 aquatic 的代码块也无法执行,具体例子如下:

class Animal{  
    public function breathe(string $animal,string $type){  
        if ($type == "terrestrial") {
            t=1;// 引入了错误
            echo $animal . "呼吸空气";  
        } else {
            echo $animal . "呼吸水";  
        }

    }  
}  

$animal = new Animal();  
$animal->breathe("牛","terrestrial");  
$animal->breathe("羊","terrestrial");  
$animal->breathe("猪","terrestrial");  
$animal->breathe("鱼","aquatic"); // 因为引入了错误导致程序无法执行

我们可以通过初始化 Terrestrial 和 Aquatic 两个类分别处理陆地动物和水中动物,这样即便是我们 Terrestrial 在处理新需求时引入了 bug 也不会导致 Aquatic 的异常。

class Terrestrial{  
    public function breathe(string $animal){  
       echo $animal . "呼吸空气";  
    }  
}  

class Aquatic{  
    public function breathe(string $animal){  
      echo $animal . "呼吸水";      
    }  
}  

try {
    $terrestrialAnimal = new Terrestrial();  
    $terrestrialAnimal->breathe("牛");  
    $terrestrialAnimal->breathe("羊");  
    $terrestrialAnimal->breathe("猪");  
} catch(\Throwable $e) {
    // 在实际场景中 Terrestrial 和 Aquatic 通常不会再一个地方调用,这里为了演示方便通过 catch 模拟真实场景

}
$aquaticAnimal = new Aquatic(); 
$aquaticAnimal->breathe("鱼");

单一职责的优势

增加代码复用: 单一职责会把代码封装的粒度变的更小,这样更有利于代码的复用。

降低单元测试难度: 符合单一职责设计的代码可以更简单的进行单元测试

降低 BUG 的产生: 符合单一职责的模块,能够限制修改代码的影响范围,不会因为某处代码的修改,引起另一处产生了 BUG。

总结

单一职责是面向对象设计的基本原则之一,了解了单一职责能够让我们的代码更健壮,更容易复用和扩展。

在需要修改原有代码的场景下,我们需要更加注意此次的更改有没有破坏模块的单一职责,以免造成程序架构的破坏。