solid 设计原则 php,PHP设计模式的六大设计原则

PHP设计模式的六大设计原则

1 简介

软件设计最大的难题就是应对需求的变化,但是纷繁复杂的需求变化却是不可预料的.此时,我们可以通过六大设计原则良好的应对未来的变化.

2 讲解

2.1 单一职责原则(Single Responsibility Principle)

一个类只负责一个职责

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

简单的例子,用户发送一个请求到服务器,当我们所有的操作只用一个action类来完成

$action = new action;

$action->getResp();

class action{

public function getResp(){

// 1检查路由

// 2安全检查

// 3检查缓存

// 4查询数据库及返回

// 5...

echo 'hello world';

}

}

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

那么当需求业务比如安全检查逻辑有变动时,我们都将修改这个类,繁琐而没有条理,极不容易维护.

若我们把路由-安全-缓存等都封装成类,就仅在getResp()调用即可,简单优雅.

2.2 开闭原则(Open Closed Principle)

一个软件实体比如类-模块-函数,应该对扩展开放,对修改关闭

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

小孩每天要做家庭作业

class Child{

public function doHomework( IHomework $homework ){

$homework -> finHomework();

}

}

interface IHomework{

public function finHomework();

}

class Homework implements IHomework{

private $work;

public function __construct( $work ){

$this->work = $work;

}

public function getWork(){

return $this->work;

}

public function finHomework(){

echo "do homework : $this->work ".PHP_EOL.'
';

}

}

$xiaoming = new Child();

$xiaoming -> doHomework( new Homework('math') );

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

do homework : math

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

突然有一天老实宣布,临近期中考试了,作业要做两次.考完恢复成做一次.倘若我们直接修改Homework类的finHomework函数,虽然可以解决问题,但是期中考试结束后又需要把函数改回来.最好的解决办法就是利用开闭原则:

class HomeworkTwice extends Homework{

public function __construct( $work ){

parent::__construct($work);

}

public function finHomework(){

$work = parent::getWork();

echo "do homework : ".$work." 1".PHP_EOL.'
';

echo "do homework : ".$work." 2".PHP_EOL.'
';

}

}

$xiaoming = new Child();

$xiaoming -> doHomework( new HomeworkTwice('math') );

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

do homework : math 1

do homework : math 2

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.3 里氏替换原则(Liskov Substitution Principle)

所有引用基类的地方必须能透明地使用其子类的对象

子类必须完全实现父类的方法,可以拓展自己的方法和属性.即子类可以扩展父类的功能,但不能改变父类原有的功能

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

我们设计了Mp4类,它具有听歌和看视频的功能.

interface IMp4{

public function listenMusic();

public function watchVedio();

}

class Mp4 implements IMp4{

public function listenMusic(){

echo ' listenMusic'.PHP_EOL.'
';

}

public function watchVedio(){

echo ' watchVedio'.PHP_EOL.'
';

}

}

class User1{

public function litenM(IMp4 $mp4){

echo 'user1';

$mp4->listenMusic();

}

public function watchV(IMp4 $mp4){

echo 'user1';

$mp4->watchVedio();

}

}

$user1 = new User1;

$mp4 = new Mp4;

$user1->litenM($mp4);

$user1->watchV($mp4);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

user1 listenMusic

user1 watchVedio

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

有一天我们要构建mp3的类,继续依照mp4的接口来生成类的话,会发现播放视频的功能用不了.

class Mp3 implements IMp4{

public function listenMusic(){

echo ' listenMusic'.PHP_EOL.'
';

}

public function watchVedio(){

//不能播放视频

}

}

$user1 = new User1;

$mp3 = new Mp3;

$user1->litenM($mp3);

$user1->watchV($mp3);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

user1 listenMusic

user1

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

此时我们可以构造IMp3接口来适应此种情况,我们还可以拓展处lookMini功能函数,符合里氏替换原则.

interface IMp3{

public function listenMusic();

}

class Mp3 implements IMp3{

public function listenMusic(){

echo ' listenMusic'.PHP_EOL.'
';

}

public function lookMini(){

echo ' lookMini'.PHP_EOL.'
';

}

}

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.4 迪米特法则(Law of Demeter)

一个对象应该对其他对象保持最少的了解

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

系统判定英雄是否赢取lol游戏,需要观察英雄完成三步:清理兵线-推塔-胜利.

class Hero{

//清理兵线

public function cleanLine(){

echo ' killed little soldiers '.PHP_EOL.'
';

return true;

}

//推塔

public function pushtower(){

echo ' destroyed their towers '.PHP_EOL.'
';

return true;

}

//胜利

public function vitory(){

echo ' victory '.PHP_EOL.'
';

}

}

class system{

public function judgeVictory(Hero $hero){

if($hero->cleanLine()){

if($hero->pushtower()){

$hero->vitory();

}

}

}

}

$system = new system;

$jax = new Hero;

$system->judgeVictory($jax);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

killed little soldiers

destroyed their towers

victory

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

以上的Hero类中暴露了太多方法给system类,两者的耦合关系异常牢固.以下设计方法可以解决此问题.

class Hero{

//清理并线

private function cleanLine(){

echo ' killed little soldiers '.PHP_EOL.'
';

return true;

}

//推塔

private function pushtower(){

echo ' destroyed their towers '.PHP_EOL.'
';

return true;

}

//胜利

private function vitory(){

echo ' victory '.PHP_EOL.'
';

}

//获取胜利

public function getVictory(){

if($this->cleanLine()){

if($this->pushtower()){

$this->vitory();

}

}

}

}

class player{

public function playLol(Hero $hero){

$hero->getVictory();

}

}

$player = new player;

$jax = new Hero;

$player->playLol($jax);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.5 接口隔离原则(INterface Segregation Principle)

类间的依赖应该建立在最小的接口上。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

有两个手机用户,用户1拿手机听歌,用户2拿手机打游戏接电话,场景实现如下:

interface IPhone{

public function call();

public function playGame();

public function listenMusic();

}

class Phone1 implements IPhone{

public function call(){

echo 'Phone1 call'.PHP_EOL.'
';

}

public function playGame(){

echo 'Phone1 playGame'.PHP_EOL.'
';

}

public function listenMusic(){

echo 'Phone1 listenMusic'.PHP_EOL.'
';

}

}

class Phone2 implements IPhone{

public function call(){

echo 'Phone2 call'.PHP_EOL.'
';

}

public function playGame(){

echo 'Phone2 playGame'.PHP_EOL.'
';

}

public function listenMusic(){

echo 'Phone2 listenMusic'.PHP_EOL.'
';

}

}

class User1{

public function litenM(IPhone $phone){

echo 'user1 use ';

$phone->listenMusic();

}

}

class User2{

public function playG(IPhone $phone){

echo 'user2 use ';

$phone->playGame();

}

public function call(IPhone $phone){

echo 'user2 use ';

$phone->call();

}

}

$phone1 = new Phone1;

$user1 = new User1;

$user1->litenM($phone1);

$phone2 = new Phone2;

$user2 = new User2;

$user2->playG($phone2);

$user2->call($phone2);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

我们发现,接口 IPhone 中出现的方法,不管依赖于它的类有没有作用,实现类的时候都要实现这些方法.若我们依据接口隔离原则,便可以解决以上问题.

interface IlandlineTelephone{

public function call();

}

interface IGameMachine{

public function playGame();

}

interface IMp3{

public function listenMusic();

}

/*interface IPhone extends IlandlineTelephone,IGameMachine,IMp3{

}*/

interface IPhone1 extends IMp3{

}

interface IPhone2 extends IlandlineTelephone,IGameMachine{

}

class Phone1 implements IPhone1{

public function listenMusic(){

echo 'Phone1 listenMusic'.PHP_EOL.'
';

}

}

class Phone2 implements IPhone2{

public function call(){

echo 'Phone2 call'.PHP_EOL.'
';

}

public function playGame(){

echo 'Phone2 playGame'.PHP_EOL.'
';

}

}

class User1{

public function litenM(IPhone1 $phone){

echo 'user1 use ';

$phone->listenMusic();

}

}

class User2{

public function playG(IPhone2 $phone){

echo 'user2 use ';

$phone->playGame();

}

public function call(IPhone2 $phone){

echo 'user2 use ';

$phone->call();

}

}

$phone1 = new Phone1;

$user1 = new User1;

$user1->litenM($phone1);

$phone2 = new Phone2;

$user2 = new User2;

$user2->playG($phone2);

$user2->call($phone2);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.6 依赖倒置原则(Dependence Inversion Principle)

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

以下是用户吃晚餐的场景:

class Rice{

public function taste(){

echo ' rice is delicious'.PHP_EOL.'
';

}

}

class User{

public function haveDinner(Rice $rice){

$rice->taste();

}

}

$user = new User;

$rice = new Rice;

$user->haveDinner($rice);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

soup is delicious

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

但是如果我们不止吃米饭,还喝汤呢,发现Rice并不适用了。我们引入一个抽象的接口Ifood,代表读物。让Mother类与接口Ifood发生依赖关系,而Rice和Soup都属于食物的范畴,让他们各自都去实现IReader接口,这样就符合高层不应该依赖低层,应该依赖于接口的依赖倒置原则,修改后代码如下:

用户吃完米饭后想要喝点汤,我们发现 haveDinner() 方法的依赖 Rice 不再适用.此时我们若依赖倒置,将haveDinner与更大范围的Ifood进行依赖,而Rice 和 Soup 实现Ifood接口,就可以解决所述问题.

interface Ifood{

public function taste();

}

class Rice implements Ifood{

public function taste(){

echo ' rice is delicious'.PHP_EOL.'
';

}

}

class Soup implements Ifood{

public function taste(){

echo ' soup is delicious'.PHP_EOL.'
';

}

}

class User{

public function haveDinner(Ifood $food){

$food->taste();

}

}

$user = new User;

$rice = new Rice;

$soup = new Soup;

$user->haveDinner($rice);

$user->haveDinner($soup);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

rice is delicious

soup is delicious

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

3 结尾

六大设计原则的首字母联合起来为SOLID-稳定的(两个L合成一个).使用六大设计原则,可以建立灵活健壮的系统.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值