面向对象设计的五大原则:单一职责原则、接口隔离原则、开放-封闭原则、替换原则、依赖倒置原则。这些原则主要是由Robert C.Martin在《敏捷软件开发——原则、方法、与实践》一书中总结出来,这五大原则也是23种设计模式的基础。

单一职责原则 Single Pesponsibility Principle, SRP

在MVC框架中,对于表单插入数据库字段过滤与安全检查应该是放在control层处理还是model层处理,这类问题都可以归到单一职责的范围。

单一职责有两个含义:

  1. 避免相同的职责分散到不同的类中
  2. 一个类承担太多职责

遵守SRP的好处:

  1. 减少类之间的耦合
  2. 提高类的复用性

在实际代码开发中的应用:工厂模式、命令模式、代理模式等。
工厂模式(Factory)允许在代码执行时实例化对象。之所以被称为工厂模式是因为它负责“生产”对象。以数据库为例,工厂需要的就是根据不同的参数,生成不同的实例化对象。它只负责生产对象,而不负责对象的具体内容。

定义一个适配器接口:

<?php
interface DbAdapter
{/*** 数据库连接* @param $config 数据库配置* @return resource*/public function connect($config);/*** 执行数据库查询* @param string $query 数据库查询SQL字符串* @param mixed $handle 连接对象* @return resource*/public function query($query, $handle);
}
?>

定义MySQL数据库操作类:

<?php
class DbAdapterMysql implements DbAdapter
{private $_dbLink; //数据库连接字符串表示/*** 数据库连接函数* @param $config 数据库配置* @throws DbException* @return resource*/public function connect($config){if($this->_dbLink = @mysql_connect($config->host .(empty($config->port) ? '' : ':' . $config->port),$config->user, $config->password, true)) {if(@mysql_select_db($config->database, $this->_dbLink)){if($config->charset){mysql_query("SET NAMES '{$config->charset}'", $this->_dbLink);}return $this->_dbLink;}}//数据库异常throw new DbException(@mysql_error($this->_dbLink));}/*** 执行数据库查询* @param string $query 数据库查询SQL字符串* @param mixed $handle 连接对象* @return resource*/public function query($query, $handle){if ($resource = @mysql_query($query, $handle)) {return $resource;}}
}
?>

SQLite数据库操作类:

<?php
class DbAdapterSqlite implements DbAdapter
{private $_dbLink;/*** 数据库连接函数* @param $config 数据库配置* @throws DbException* @return resource*/public function connect($config){if ($this->_dbLink = sqlite_open($config->file, 0666, $error)) {return $this->_dbLink;}throw new DbException($error);}/*** 执行数据库查询* @param string $query 数据库查询SQL字符串* @param mixed $handle 连接对象* @return resource*/public function query($query, $handle){if ($resource = @sqlite_query($query, $handle)) {return $resource;}}
}
?>

定义一个工厂类,根据传入不同的参数生成需要的类:

<?phpclass sqlFactory{public static function factory($type){if (include_once 'Drivers/' . $type . '.php') {$classname = 'DbAdapter' . $type;return new $classname;} else {throw new Exception('Driver not found');}}}
?>

调用:

$db = sqlFactory::factory('MySQL');
$db = sqlFactory::factory('SQLite');

命令模式分离“命令的请求者”和“命令的实现者”方面的职责。

<?php
/**
* 厨师类,命令接受者与执行者
*/
class cook
{public function meal(){echo '番茄炒鸡蛋',PHP_EOL;}public function drink(){echo '紫菜蛋花汤',PHP_EOL;}public function ok(){echo '完毕',PHP_EOL;}
}/**
* 命令接口
*/
interface Command{public function execute();
}
?>

模拟服务员与厨师的过程:

<?php
class MealCommand implements Command
{private $cook;//绑定命令接受者public function __construct(cook $cook){$this->cook = $cook;}public function execute(){$this->cook->meal();//把消息传递给厨师,让厨师做饭}
}class DrinkCommand implements Command
{private $cook;//绑定命令接受者public function __construct(cook $cook){$this->cook = $cook;}public function execute(){$this->cook->drink();}
}
?>

模拟顾客与服务员的过程:

<?php
class cookControl
{private $mealCommand;private $drinkCommand;//将命令发送者绑定到命令接收器public function addCommand(Command $mealCommand, Command $drinkCommand){$this->mealCommand = $mealCommand;$this->drinkCommand = $drinkCommand;}public function callMeal(){$this->mealCommand->execute();}public function callDrink(){$this->drinkCommand->execute();}
}
?>

实现命令模式:

$control = new cookControl;
$cook = new cook;
$mealCommand = new MealCommand($cook);
$drinkCommand = new DrinkCommand($cook);
$control->addCommand($mealCommand, $drinkCommand);
$control->callMeal();
$control->callDrink();

接口隔离原则 Interface Segregation Principle,ISP
接口隔离原则(Interface Segregation Principle,ISP)表明客户端不应该被强迫实现一些不会使用的接口,应该把胖接口分组,用多个接口代替它,每个接口服务于一个子模块。简单地说,就是使用多个专门的接口比使用单个接口要好很多。
ISP主要观点:
1.一个类对另外一个类的依赖性应当是建立在最小接口上的。
ISP可以达到不强迫客户(接口使用者)依赖于他们不用的方法,接口的实现类应该只呈现为单一职责的角色(遵守SRP原则)。
ISP可以降低客户之间的相互影响——当某个客户程序要求提供新的职责(需求变化)而迫使接口发生变化时,影响到其他客户程序的可能性会最小。
2.客户端程序不应该依赖它不需要的接口方法(功能)。

ISP强调的是接口对客户端的承诺越少越好,并且要做到专一。
接口污染就是为接口添加不必要的职责。“接口隔离”其实就是定制化服务设计的原则。使用接口的多重继承实现对不同的接口的组合,从而对外提供组合功能——达到“按需提供服务”。

对于接口的污染,使用下面两种处理方式:

  • 利用委托分离接口。
  • 利用多继承分离接口。

委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理,如策略模式、代理模式等都应用到了委托的概念。

开放-封闭原则
随着软件系统的规模不断增大,软件系统的维护和修改的复杂性不断提高,这种困境促使法国工程院士Bertrand Meyer在1998年提出了“开放-封闭”(Open-Close Principle, OCP)原则,基本思想是:
Open(Open for extension)模块的行为必须是开放的、支持扩展的,而不是僵化的。
Closed(Closed for modification)在对模块的功能进行扩展时,不应该影响或大规模地影响已有的程序模块。

换句话说,也就是要求开发人员在不修改系统中现有功能代码(源代码或二进制代码)的前提下,实现对应用系统的软件功能的扩展。用一句话概括就是:一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的
开放-封闭能够提高系统的可扩展性和可维护性,但这也是相对的。
以播放器为例,先定义一个抽象的接口:

interface Process
{public function process();
}

然后对此接口进行扩展,实现解码和输出的功能:

class playerEncode implements Proess
{public function process(){echo "encode\r\n";}
}    class playerOutput implements Process
{public function process(){echo "output\r\n";}
}

对于播放器的各种功能,这里是开放的。只要你遵守约定,实现了process接口,就能给播放器添加新的功能模块。
接下来为定义播放器的线程调度管理器,播放器一旦接收到通知(可以是外部单击行为,也可以是内部的notify行为),将回调实际的线程处理:

class playProcess
{private $message = null;public function __construct(){}public function callback(Event $event){$this->message = $event->click();if($this->message instanceof Process){$this->message->process();}}
}

具体的产品出来了,在这里定义一个MP4类,这个类是相对封闭的,其中定义事件的处理逻辑:

class MP4
{public function work(){$playProcess = new playProcess();$playProcess->callback(new Event('encode'));$playProcess->callback(new Event('output'));}
}

最后为事件分拣的处理类,此类负责对事件进行分拣,判断用户或内部行为,以产生正确的“线程”,供播放器内置的线程管理器调度:

class Event
{private $m;public function __construct($me){$this->m = $me;}public function click(){switch($this->m){case 'encode':return new playerEncode();break;case 'output':return new playerOutput();break;    }}
}

运行:

$mp4 = new MP4;
$mp4->work();
//打印结果
encode
output

如何遵守开放-封闭原则
实现开放-封闭的核心思想就是抽象编程的核心思想就是对抽象编程,而不是对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,这样的修改就是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有的行为,实现新的扩展方法,所以对于扩展就是开放的。
1.在设计方面充分应用“抽象”和封装的思想。
一方面就是要在软件系统中找出各种可能的“可变因素”,并将之封装起来;另一方面,一种可变性因素不应当散落在多个不同代码模块中,而应当被封装到一个对象中。
2.在系统功能编程实现方面应用面向接口编程。
当需求发生变化时,可以提供该接口新的实现类,以求适应变化。
面向接口编程要求功能类实现接口,对象声明为接口类型。再设计模式中,装饰模式比较明显地用到OCP。

替换原则
替换原则也称里氏替换原则(Liskov Substitution Principle, LSP)的定义和主要思想如下:由于面向对象编程技术中的继承在具体的编程中过于简单,在许多系统的设计和编程实现中,我们并没有认真地、理性地思考应用系统中各个类之间的继承关系是否合适,派生类是否能正确地对其基类中的某些方法进行重写等问题。因此经常出现滥用继承或者错误地进行了继承等现象,给系统的后期维护带来不少麻烦。
LSP指出:子类型必须能够替换掉它们的父类型,并出现在父类能够出现的任何地方
LSP主要是针对继承的设计原则,继承与派生(多态)是OOP的主要特性。
如何遵守LSP设计原则:

  • 父类的方法都要在子类中实现或重写,并且派生类只实现其抽象类中声明的方法,而不应当给出多余的方法定义或实现。

在客户段程序中只应该使用父类对象而不应当直接使用子类对象,这样可以实现运行期绑定(动态绑定)。
如果A、B两个类违反了LSP的设计,通常的做法是创建一个新的抽象类C,作为两个具体类的超类,将A和B的共同行为移到C中,从而解决A和B行为不完全一致的问题。

依赖倒置原则 Dependence Inversion Principle, DIP
依赖倒置简单地讲就是将依赖关系倒置为依赖接口,具体概念如下:

  • 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象(父类不能依赖子类,它们都要依赖抽象类)。
  • 抽象不能依赖于具体,具体应该依赖于抽象。

为什么要依赖接口?因为接口体现对问题的抽象,同时由于抽象一般是相对稳定的或者是相对变化不频繁的,而具体是易变的。因此,依赖抽象是实现代码扩展和运行期内绑定(多态)的基础:只要实现了该抽象类的子类,都可以被类的使用者使用。

<?php
interface employee
{public function working();
}class teacher implements employee
{public function working(){echo 'teaching...';}
}class coder implements employee
{public function working(){echo 'coding...';}
}class workA
{public function work(){$teacher = new teacher;$teacher->working();}
}class workB
{private $e;public function set(employee $e){$this->e = $e;}public function work(){$this->e->working();}
}$worka = new workA;
$worka->work();
$workb = new workB;
$workb->set(new teacher());
$workb->work();

在workA中,work方法依赖于teacher实现;在workB中,work转而依赖于抽象,这样可以把需要的对象通过参数传入。
在workB中,teacher实例通过setter方法传入,从而实现了工厂模式。由于这样的是实现是硬编码的,为了实现代码的进一步扩展,把这个依赖关系写在配置文件里,指明workB需要一个teacher对象,专门由一个程序检测配置是否正确(如所依赖的类文件是否存在)以及加载配置中所依赖的实现,这个检测程序,就称为IOC容器。
IOC(Inversion Of Control)是依赖倒置原则(Dependence Inversion Principle, DIP)的同义词。依赖注入(DI)和依赖查找(DS)是IOC的两种实现。

PHP面向对象设计的五大原则相关推荐

  1. solid 设计原则 php,面向对象设计SOLID五大原则

    今天我给大家带来的是面向对象设计SOLID五大原则的经典解说. 我们知道,面向对象对于设计出高扩展性.高复用性.高可维护性的软件起到很大的作用.我们常说的SOLID五大设计原则指的就是: S = 单一 ...

  2. java五大原则_Java成长第五集--面向对象设计的五大原则

    S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则(Programming Priciple)的首字母缩写.以下图说明: 下面就个人的理解来说说这五大原则的含义到 ...

  3. Java成长第五集--面向对象设计的五大原则

    S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则(Programming Priciple)的首字母缩写.以下图说明: 下面就个人的理解来说说这五大原则的含义到 ...

  4. 61条面向对象设计的经验原则

    61条面向对象设计的经验原则 摘抄自<OOD 启思录>--Arthur J.Riel 著 鲍志云 译 "你不必严格遵守这些原则,违背它们也不会被处以宗教刑罚.但你应当把这些原则看 ...

  5. 深入理解面向对象设计的七大原则

    一.面向对象设计的七大原则是什么? 1.开放封闭原则 2.里氏转换原则 3.依赖倒转原则 4.组合/聚合原则 5.接口隔离原则 6."迪米特"法则 7.单一职责原则 二.七大原则是 ...

  6. java中高级面试_中高级面试常问:Java面向对象设计的六大原则

    这篇文章主要讲的是面向对象设计中,我们应该遵循的六大原则.只有掌握了这些原则,我们才能更好的理解设计模式.我们接下来要介绍以下6个内容.单一职责原则--SRP 开闭原则--OCP 里式替换原则--LS ...

  7. LOGO设计的五大原则

    LOGO设计的五大原则 一个logo设计的好坏,能够推动一个品牌的发展,好的LOGO设计依然是遵循一些最基本的原则的.当你在构思新的LOGO之时,可以试着从下面5个关键设计原则的角度来思考. 1.简单 ...

  8. 面向对象设计与开发原则

    介绍 这里介绍了5个面向对象设计与开发原则–SOLID原则,分别是:单一职责原则.开放封闭原则.里氏替换原则.接口隔离原则.依赖倒置原则.另外还介绍了其他3个原则:迪米特法则."Tell, ...

  9. 面向对象设计的七大原则 (包括SOLID原则)

    文章目录 概述 1. 单一原则 2. 里氏替换原则 3. 依赖倒转原则 4. 接口分隔原则(Interface Segregation Principle ,ISP) 5. 迪米特法则 (Law of ...

最新文章

  1. 天问电子少年团DIY作品
  2. python基于水色图像的水质评价_基于Python和遥感图像的膨胀与腐蚀操作
  3. Qt学习之路(58): 进程间交互
  4. 人脸识别方法个人见解
  5. 嫁给我好吗?| 今日最佳
  6. 陈丽琳:如何以大数据助力商场运营
  7. Jedis 常用API使用
  8. 【从C到C++学习笔记】引用/const引用/引用传递/引用作为函数返回值/引用和指针的区别
  9. 大群就是公共场所,不要有事就在大群说
  10. 评价指标MSE和AUC的参考文献
  11. Revit插件 | 建模助手 V1.8.52 爆炸式更新,你确定不来看看?
  12. 老婆生成器 yyds
  13. Spring-statemachine有限状态机(FSM)使用教程详解
  14. Apache DolphinScheduler 3.0.0 正式版发布!
  15. Windows常用操作—热键(快捷键)
  16. C语言实现简单的线程池【转】
  17. Java并发体系-第二阶段-锁与同步-[1]-【万字文系列】
  18. 嵌入式开发什么时候需要用RTOS?
  19. B4A +GoLang 实现手机端webserver
  20. Java静态类的使用

热门文章

  1. 深度学习—大厂笔试题
  2. win台式找不到计算机管理,win10系统计算机右键-管理打不开windows找不到文件的解决方法...
  3. linux proc sys,对/proc和/sys的一些理解
  4. vue 对象中数组中对象某个属性更改_vue之监听对象、对象数组的改变
  5. 接口测试用例设计思路_基于python语言的接口自动化demo小实战
  6. python 爱心文字墙_python奇技淫巧 | nMask's Blog
  7. 计算机软件等级认证,中国计算机学会推出软件非专业级别能力认证
  8. android 键盘遮盖输入框_android弹出输入框,软键盘挡住部分编辑框
  9. VB案例:宁越电子琴
  10. 普通变量与寄存器变量速度对比