PHP设计模式的六大设计原则
PHP设计模式的六大设计原则
1 简介
软件设计最大的难题就是应对需求的变化,但是纷繁复杂的需求变化却是不可预料的.此时,我们可以通过六大设计原则良好的应对未来的变化.
2 讲解
2.1 单一职责原则(Single Responsibility Principle)
一个类只负责一个职责
简单的例子,用户发送一个请求到服务器,当我们所有的操作只用一个action类来完成
<?php
$action = new action;
$action->getResp();
class action{
public function getResp(){
// 1检查路由
// 2安全检查
// 3检查缓存
// 4查询数据库及返回
// 5...
echo 'hello world';
}
}
那么当需求业务比如安全检查逻辑有变动时,我们都将修改这个类,繁琐而没有条理,极不容易维护.
若我们把路由-安全-缓存等都封装成类,就仅在getResp()调用即可,简单优雅.
2.2 开闭原则(Open Closed Principle)
一个软件实体比如类-模块-函数,应该对扩展开放,对修改关闭
小孩每天要做家庭作业
<?php
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.'<br/>';
}
}
$xiaoming = new Child();
$xiaoming -> doHomework( new Homework('math') );
do homework : math
突然有一天老实宣布,临近期中考试了,作业要做两次.考完恢复成做一次.倘若我们直接修改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.'<br/>';
echo "do homework : ".$work." 2".PHP_EOL.'<br/>';
}
}
$xiaoming = new Child();
$xiaoming -> doHomework( new HomeworkTwice('math') );
do homework : math 1
do homework : math 2
2.3 里氏替换原则(Liskov Substitution Principle)
所有引用基类的地方必须能透明地使用其子类的对象
子类必须完全实现父类的方法,可以拓展自己的方法和属性.即子类可以扩展父类的功能,但不能改变父类原有的功能
我们设计了Mp4类,它具有听歌和看视频的功能.
interface IMp4{
public function listenMusic();
public function watchVedio();
}
class Mp4 implements IMp4{
public function listenMusic(){
echo ' listenMusic'.PHP_EOL.'<br/>';
}
public function watchVedio(){
echo ' watchVedio'.PHP_EOL.'<br/>';
}
}
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);
user1 listenMusic
user1 watchVedio
有一天我们要构建mp3的类,继续依照mp4的接口来生成类的话,会发现播放视频的功能用不了.
class Mp3 implements IMp4{
public function listenMusic(){
echo ' listenMusic'.PHP_EOL.'<br/>';
}
public function watchVedio(){
//不能播放视频
}
}
$user1 = new User1;
$mp3 = new Mp3;
$user1->litenM($mp3);
$user1->watchV($mp3);
user1 listenMusic
user1
此时我们可以构造IMp3接口来适应此种情况,我们还可以拓展处lookMini功能函数,符合里氏替换原则.
interface IMp3{
public function listenMusic();
}
class Mp3 implements IMp3{
public function listenMusic(){
echo ' listenMusic'.PHP_EOL.'<br/>';
}
public function lookMini(){
echo ' lookMini'.PHP_EOL.'<br/>';
}
}
2.4 迪米特法则(Law of Demeter)
一个对象应该对其他对象保持最少的了解
系统判定英雄是否赢取lol游戏,需要观察英雄完成三步:清理兵线-推塔-胜利.
class Hero{
//清理兵线
public function cleanLine(){
echo ' killed little soldiers '.PHP_EOL.'<br/>';
return true;
}
//推塔
public function pushtower(){
echo ' destroyed their towers '.PHP_EOL.'<br/>';
return true;
}
//胜利
public function vitory(){
echo ' victory '.PHP_EOL.'<br/>';
}
}
class system{
public function judgeVictory(Hero $hero){
if($hero->cleanLine()){
if($hero->pushtower()){
$hero->vitory();
}
}
}
}
$system = new system;
$jax = new Hero;
$system->judgeVictory($jax);
killed little soldiers
destroyed their towers
victory
以上的Hero类中暴露了太多方法给system类,两者的耦合关系异常牢固.以下设计方法可以解决此问题.
class Hero{
//清理并线
private function cleanLine(){
echo ' killed little soldiers '.PHP_EOL.'<br/>';
return true;
}
//推塔
private function pushtower(){
echo ' destroyed their towers '.PHP_EOL.'<br/>';
return true;
}
//胜利
private function vitory(){
echo ' victory '.PHP_EOL.'<br/>';
}
//获取胜利
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);
2.5 接口隔离原则(INterface Segregation Principle)
类间的依赖应该建立在最小的接口上。
有两个手机用户,用户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.'<br/>';
}
public function playGame(){
echo 'Phone1 playGame'.PHP_EOL.'<br/>';
}
public function listenMusic(){
echo 'Phone1 listenMusic'.PHP_EOL.'<br/>';
}
}
class Phone2 implements IPhone{
public function call(){
echo 'Phone2 call'.PHP_EOL.'<br/>';
}
public function playGame(){
echo 'Phone2 playGame'.PHP_EOL.'<br/>';
}
public function listenMusic(){
echo 'Phone2 listenMusic'.PHP_EOL.'<br/>';
}
}
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);
我们发现,接口 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.'<br/>';
}
}
class Phone2 implements IPhone2{
public function call(){
echo 'Phone2 call'.PHP_EOL.'<br/>';
}
public function playGame(){
echo 'Phone2 playGame'.PHP_EOL.'<br/>';
}
}
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);
2.6 依赖倒置原则(Dependence Inversion Principle)
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
以下是用户吃晚餐的场景:
class Rice{
public function taste(){
echo ' rice is delicious'.PHP_EOL.'<br/>';
}
}
class User{
public function haveDinner(Rice $rice){
$rice->taste();
}
}
$user = new User;
$rice = new Rice;
$user->haveDinner($rice);
soup is delicious
但是如果我们不止吃米饭,还喝汤呢,发现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.'<br/>';
}
}
class Soup implements Ifood{
public function taste(){
echo ' soup is delicious'.PHP_EOL.'<br/>';
}
}
class User{
public function haveDinner(Ifood $food){
$food->taste();
}
}
$user = new User;
$rice = new Rice;
$soup = new Soup;
$user->haveDinner($rice);
$user->haveDinner($soup);
rice is delicious
soup is delicious
3 结尾
六大设计原则的首字母联合起来为SOLID-稳定的(两个L合成一个).使用六大设计原则,可以建立灵活健壮的系统.
PHP设计模式的六大设计原则的更多相关文章
- IOS设计模式的六大设计原则之开放-关闭原则(OCP,Open-Close Principle)
定义 一个软件实体(如类.模块.函数)应当对扩展开放,对修改关闭. 定义解读 在项目开发的时候,都不能指望需求是确定不变化的,大部分情况下,需求是变化的.那么如何应对需求变化的情况?这就是开放-关闭原 ...
- IOS设计模式的六大设计原则之单一职责原则(SRP,Single Responsibility Principle)
定义 就一个类而言,应该仅有一个引起它变化的原因. 定义解读 这是六大原则中最简单的一种,通俗点说,就是不存在多个原因使得一个类发生变化,也就是一个类只负责一种职责的工作. 优点 类的复杂度降低,一个 ...
- IOS设计模式的六大设计原则之迪米特法则(LOD,Law Of Demeter)
定义 狭义的迪米特法则定义:也叫最少知识原则(LKP,Least Knowledge Principle).如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中的一个类需要调用 ...
- php设计模式之六大设计原则
1.单一职责 定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责. 场景:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致 ...
- IOS设计模式的六大设计原则之依赖倒置原则(DIP,Dependence Inversion Principle)
定义 高层模块不应该依赖于低层模块,二者都应该依赖于抽象:抽象不应该依赖细节:细节应该依赖抽象. 定义解读 依赖倒置原则在程序编码中经常运用,其核心思想就是面向接口编程,高层模块不应该依赖低层模块(原 ...
- IOS设计模式的六大设计原则之接口隔离原则(ISP,Interface Segregation Principle)
定义 客户端不应该依赖它不需要的接口: 一个类对另一个类的依赖应该建立在最小的接口上. 定义解读 定义包含三层含义: 一个类对另一个类的依赖应该建立在最小的接口上: 一个接口代表一个角色,不应该将不同 ...
- IOS设计模式的六大设计原则之里氏替换原则(LSP,Liskov Substitution Principle)
定义 里氏替换原则的定义有两种,据说是由麻省理工的一位姓里的女士所提出,因此以其名进行命名. 定义1:如果对一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1所定义的程序P中在o1全都替换 ...
- iOS----------设计模式的六大设计原则------>开放-关闭原则(OCP,Open-Close Principle)
定义 一个软件实体(如类.模块.函数)应当对扩展开放,对修改关闭. 定义解读 在项目开发的时候,都不能指望需求是确定不变化的,大部分情况下,需求是变化的.那么如何应对需求变化的情况?这就是开放-关闭原 ...
- 十年阿里java架构师的六大设计原则和项目经验
先看一幅图吧: 这幅图清晰地表达了六大设计原则,但仅限于它们叫什么名字而已,它们具体是什么意思呢?下面我将从原文.译文.理解.应用,这四个方面分别进行阐述. 1.单一职责原则(Single Res ...
随机推荐
- python中线程和进程(一)
目录 进程和线程 Python中的线程 1. Thread类 2. 线程的启动 3. 线程的传参 4. 线程的属性和方法 5. daemon线程和non-daemon线程 6. join方法 7. 定 ...
- ASP.NET Core开发者成长路线图
目录 ASP.NET Core开发者路线图RoadMap 免责声明 请给一个星星! ⭐ 路线图 资源 总结 贡献 许可协议 ASP.NET Core开发者路线图RoadMap 来源: MoienTaj ...
- CAP带你轻松玩转Asp.Net Core消息队列
CAP是什么? CAP是由我们园子里的杨晓东大神开发出来的一套分布式事务的决绝方案,是.Net Core Community中的第一个千星项目(目前已经1656 Star),具有轻量级.易使用.高性能 ...
- 【干货分享】可能是东半球最全的.NET Core跨平台微服务学习资源
如果你发现还有西半球的资源,烦请相告,不胜感谢! 一..NET Core基础 微软英文官网 .NET Core 微软中文官网 GitHub 用ASP.NET内核和Azure构建现代Web应用程序 博客 ...
- 设计模式之过滤器模式——Java语言描述
过滤器模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来 实现 创建一个Person对象.Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列 ...
- openlayers4 入门开发系列之风场图篇
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
- 通过免费开源ERP构建业界领先的供应链+垂直电商平台成功案例分享
案例客户简介 Healey Green是一家新成立的企业,在线销售和销售园艺机械. 他们的产品范围包括草坪割草机,割灌机,地钻,链锯等. 在一个竞争非常激烈的市场中,这位雄心勃勃的新人将开始接受那些以 ...
- Windows系统配置OutLook邮箱教程一
本示例演示Windows系统中OutLook邮箱设置 1.打开控制面板->类型选择小图标->找到Mail(Microsoft OutLook 2016). 2.鼠标左键双击Mail. 3. ...
- 随笔:WPS居然!出了!Mac版!
震惊! WPS! 居然! 出了! Mac版! 刚刚,我打算改一个word文档,打开了我的WIN10虚拟机,然而由于这个win10是前两天重装的,上面并没有word和wps. 当我打开wps官网的时候, ...
- nn.ConvTranspose2d的参数output_padding的作用
参考:https://blog.csdn.net/qq_41368247/article/details/86626446 使用前提:stride > 1 补充:same卷积操作 是通过padd ...