设计模式之六大原则
php 技术群:781742505
什么是设计模式?
设计模式是人们在软件设计过程中对反复出现的各种问题提出的解决方案。
设计模式的特点:高可重用性、高可读性、高可拓展性、高可靠性等。
1. 单一职责
顾名思义,就是一个类只负责单一的职责。
反例:类有两个职责,其中一个职责变化很有可能会导致另一个职责的正常运行。
方案:上面的两个职责分别建立两个类。
<?php
class User
{
public function information()
{
}
public function updateInformation()
{
}
public function login()
{
}
public function logout()
{
}
}
登录和退出登录应该属于认证范围,所以我们应当将 User 类拆分成 User 和 Auth 类。
<?php
class User
{
public function information()
{
}
public function updateInformation()
{
}
}
class Auth
{
public function login()
{
}
public function logout()
{
}
}
2. 里氏替换
子类可以扩展父类的功能,但不能改变父类原有的功能。
方案:子类除添加新的方法完成新增功能外,尽量不要重写父类的方法,也尽量不要重载父类的方法。
好处:避免混淆代码,如下面例子。
<?php
class Computer
{
public function minus($a, $b)
{
return $a - $b;
}
}
$computer = new Computer();
echo $computer->minus(100, 50);
class AdvanceComputer extends Computer
{
public function minus($a, $b)
{
return $b - $a;
}
public function minusThenDouble($a, $b)
{
return $this->minus($a, $b) * 2;
}
}
$advanceComputer = new AdvanceComputer();
echo $advanceComputer->minusThenDouble(100, 50);
3. 依赖倒置
面向抽象编程。高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
业务逻辑层相对于数据层是高层模块,尽量不要让业务逻辑层依赖数据层,
可以在数据层抽象出一个接口,让业务逻辑层依赖于这个抽象接口。
反例:子类依赖低层类 A,有一天需要修改成子类依赖低层类 B,这时候就要修改大量代码。
方案:低层类 A 抽象出一个接口。让子类去依赖这个接口。以后要依赖低层类 B,只要 B 实现这个接口即可满足。
<?php
class Mysql
{
public function select($id)
{
echo "$id";
}
}
class User
{
public function find(Mysql $mysql, $id)
{
$mysql->select($id);
}
}
$id = 120;
(new User())->find((new Mysql()), $id);
如果 User 类的数据库从 mysql 变成了 oracle,还需要修改 User 类。
<?php
interface DB
{
public function select($id);
}
class Mysql implements DB
{
public function select($id)
{
echo "mysql $id";
}
}
class Oracle implements DB
{
public function select($id)
{
echo "oracle $id";
}
}
class User
{
public function find(DB $db, $id)
{
$db->select($id);
}
}
$id = 120;
(new User())->find((new Mysql()), $id);
echo "\n";
(new User())->find((new Oracle()), $id);
4. 接口隔离
顾名思义,接口需要隔离,为什么需要隔离,因为我们要将臃肿的接口拆分成最小接口。类似单一职责。
如果不是最小接口,就需要去实现他们不需要的接口。
5. 最少知道
类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。不要和陌生人说话,只和直接的朋友互动。
<?php
class Movie
{
public function play()
{
return "A movie is playing";
}
}
class Phone
{
public function playMovie(Movie $movie)
{
return $movie->play();
}
}
手机和电影并不是直接的朋友关系,手机里面装播放器,播放器才是电影的直接朋友。
<?php
interface Video
{
public function play();
}
class Movie implements Video
{
public function play()
{
return "卧虎藏龙播放中。。。";
}
}
class Player
{
public function playVideo(Video $video)
{
return $video->play();
}
}
class Phone
{
private $player;
public function installPlayer(Player $player)
{
$this->player = $player;
}
public function runPlayer(Video $video)
{
if ($this->player instanceof Player) {
return $this->player->playVideo($video);
} else {
return "播放器不存在";
}
}
}
$player = new Player();
$phone = new Phone();
$phone->installPlayer($player);
$movie = new Movie();
$playerStatus = $phone->runPlayer($movie);
echo $playerStatus;
6. 开闭原则
当软件需求变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
<?php
class AreaComputer
{
public $height;
public $weight;
public function area()
{
return $this->height * $this->weight;
}
}
class Rectangle extends AreaComputer
{
public function __construct($height, $weight){
$this->height = $height;
$this->weight = $weight;
}
}
echo (new Rectangle(3, 4))->area();
<?php
class AreaComputer
{
public $height;
public $weight;
public $radius;
public function area()
{
if ($this instanceof Rectangle) {
return $this->height * $this->weight;
}
return 3.14 * $this->radius * $this->radius;
}
}
class Rectangle extends AreaComputer
{
public function __construct($height, $weight){
$this->height = $height;
$this->weight = $weight;
}
}
class Circle extends AreaComputer{
public function __construct($radius){
$this->radius = $radius;
}
}
echo (new Rectangle(3, 4))->area();
echo "\n";
echo (new Circle(10))->area();
破坏了修改关闭原则
<?php
interface Shape
{
public function area();
}
class Rectangle implements Shape
{
public $height;
public $weight;
public function __construct($height, $weight)
{
$this->height = $height;
$this->weight = $weight;
}
public function area()
{
return $this->height * $this->weight;
}
}
class Circle implements Shape
{
public $radius;
public function __construct($radius)
{
$this->radius = $radius;
}
public function area()
{
return 3.14 * $this->radius * $this->radius;
}
}
echo (new Rectangle(3, 4))->area();
echo "\n";
echo (new Circle(10))->area();
此时还可以轻易拓展周长方法。