单一职责原则(Single Pesponsibility Principle, SRP)
单一职责有两个含义: 一个是避免相同的职责分散到不同的类中, 别一个是避免一个类承担太多职责
为什么要遵守SRP呢?
(1)可以减少类之间的耦合
如果减少类之间的耦合,当需求变化时,只修改一个类,从而也就隔离了变化;如果一个类有多个不同职责,它们耦合在一起,当一个职责发生变化时,可能会影响到其他职责。
(2)提高类的复用性
修改电脑比修理电视机简单多了。主要原因就在于电视机各个部件之间的耦合性太高,而电脑则不同,电脑的内存、硬盘、声卡、网卡、键盘灯等部件都可以很容易地单独拆卸和组装。某个部件坏了,换上新的即可。上面的例子就体现了单一职责的优势。由于使用了单一职责,使得‘组件’可以方便地‘拆卸’和‘组装’。
不遵守SRP会影响对类的复用性。当只需要用该类的某一个职责时,由于它和其他的职责耦合在一起,也就很难分离出。
遵守SRP在实际代码开发中有没有什么应用?有的。以数据持久层为例,所谓的数据持久层主要指的是数据库操作,当然,还包括缓存管理等。这时就需要数据持久层支持多种数据库。应该怎么做?定义多个数据库操作类?想法已经很接近了,再进一步,就是使用工厂模式。
工厂模式(Faction)允许你在代码执行时实例化对象。它之所以被称为工厂模式是因为它负责‘生产对象’。以数据库为例,工厂需要的就是根据不同的参数,生成不同的实例化对象。最简单的工厂就是根据传入的类型名实例化对象,如传入MySQL,就调用MySQL类并实例化,如果是SQLite,则调用 SQLite的类并实例化,甚至还可以处理TXT、Execl等‘类数据库’。
工厂类也就是这样的一个类,它只负责生产对象,而不负责对象的具体内容。

以下是示例
定义一个适配器的接口
interface Db_Adpater
{/*** 数据库连接* @param $config 数据库配置* @return mixed resource*/public function connect($config);/*** 执行数据库查询* @param $query 数据库查询的SQL字符串* @param $handle  连接对象* @return mixed*/public function query($query,$handle);
}

定义一个实现了DB_Adpater接口的MySQL数据库操作类
class Db_Adapter_Mysql implements Db_Adpater
{private $_dbLink;   //数据库连接字符串标识/*** 数据库连接函数* @param $config 数据库配置* @return resource* @throws Db_Exception*/public function connect($config){if($this->_dbLink = @mysql_connect($config->host . (empty($config->port) ? '' : ':' . $config->prot) ,$config->user, $config->password, true)){if(@mysql_select_db($config->database, $this->_dbLink)){if($config->charset){mysql_query("SET NAME '{$config->charset}'", $this->_dbLink);}return $this->_dbLink;}}throw new Db_Exception(@mysql_error($this->_dbLink));}/*** 执行数据库查询* @param $query 数据库查询SQL字符串* @param $handle 连接对象* @return resource*/public function query($query,$handle){if($resource = @mysql_query($query,$handle))return $resource;}
}

定义一个实现了DB_Adpater接口的SQLite数据库操作类

class Db_Adapter_sqlite implements Db_Adpater
{private $_dbLink;   //数据库连接字符串标识public function connect($config){if($this->_dbLink = sqlite_open($config->file, 0666, $error)){return $this->_dbLink;}throw new Db_Exception($error);}public function query($query, $handle){if($resource = @sqlite_query($query,$handle)){return $resource;}}
}

现在如果需要一个数据库操作的方法怎么做,只需定义一个工厂类,根据传入不同的生成需要的类即可

class sqlFactory
{public static function factory($type){if(include_once 'Drivers/' . $type . '.php'){$classname = 'Db_Adapter_'.$type;return new $classname;}elsethrow new Exception('Driver not found');}
}

调用时,就可以这么写

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

我们把创建数据库连接这块程序单独拿出来,程序中的CURD就不用关心什么数据库了,只要按照规范使用对应的方法即可。
工厂方法让具体的对象解脱出来,使其不再依赖具体的类,而是抽象。

设计模式里面的命令模式也是SRP的体现,命令模式分离“命令的请求者”和“命令的实现者”方面的职责。举一个很好理解的例子,就是你去餐馆订餐吃饭,餐馆存在顾客、服务员、厨师三个角色。作为顾客,你要列出菜单,传给服务员,由服务员通知厨师去实现。作为服务员,只需要调用准备饭菜这个方法(对厨师喊“该炒菜了”),厨师听到要炒菜的请求,就立即去做饭。在这里,命令的请求和实现就完成了解耦。
模拟这个过程,首先定义厨师角色,厨师进行实际做饭、烧汤的工作。
以下是示例

/*** 厨师类,命令接受者与执行者* Class cook*/
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();
}

轮到服务员出场,服务员是命令的传送者,通常你到饭馆吃饭都是叫服务员吧,不能直接叫厨师,一般都是叫“服务员,给我来盘番茄炒西红柿”。所以,服务员是顾客和厨师之间的命令沟通都。

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();}
}

现在顾客可以按照菜单叫服务员了

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();

从上面的例子可以看出,原来设计模式并非纯理论的东西,而是来源于实际生活,就连普通的餐馆老板都懂设计模式这门看似高深的学问。其实,在经济和管理活动中对流程的优化就是对各种设计模式的摸索和实践。所以,设计模式并非计算机编程中的专利。事实上,设计模式的起源并不是计算机,而是源于建筑学。
在设计模式方面,不仅以上这两种体现了SRP,还有别的(比如代理模式)也体现了SRP。SRP不只是对类设计有意义,对以模块、子系统为单位的系统架构设计同样有意义。
模块、子系统也应该仅有一个引起它变化的原因,如MVC所倡导的各个层之间的相互分离就是SRP在系统总体设计中的应用。
SRP是最简单的原则之一,也是最难做好的原则之一。我们会很自然地将职责连接在一起。找到并且分离这些职责是软件设计需要达到的目的
一些简单的应用遵循的做法如下:
根据业务流程,把业务对象提炼出来。如果业务的流程的链路太复杂,就把这个业务对象分离为多个单一业务对象。当业务链标准化后,对业务对象的内部情况做进一步处理,把第一次标准化视为最高层抽象,第二次视为次高层抽象,以此类推,直到“恰如其分”的设计层次
职责的分类需要注意。有业务职责,还要有脱离业务的抽象职责,从认识业务到抽象算法是一个层层递进的过程。就好比命令模式中的顾客,服务员和厨师的职责,作为老板(即设计师)的你需要规划好各自的职责范围,即要防止越俎代庖,也要防止互相推诿。

转载于:https://www.cnblogs.com/chenqionghe/p/4749915.html

单一职责原则(SRP)相关推荐

  1. [置顶]       设计模式之六大原则——单一职责原则(SRP)

    定义: 应该有且仅有一个原因引起类的变更. There should never be more than one reason for a class to change. 优点: 1.类的复杂性降 ...

  2. 围观设计模式(1)--单一职责原则(SRP,Single Responsibility Principle)

    沉寂了一个月的时间,仔细学习了下设计模式,从本篇博文开始陆续更新设计模式系列的文章,我给它起了个有意思的名字叫做:"围观"设计模式,当然围观是加引号的,我写博文分享的目的一方面是将 ...

  3. 设计模式原则--单一职责原则

    单一职责原则(SRP) 定义:就一个类而言,应该仅有一个引起它变化的原因 场景: 一个公司有3类员工,分别是 主管,程序员,销售 代码: using System; using System.Coll ...

  4. 设计模式原则篇:(1)单一职责原则--Single Responsibility Principle

    上篇文章提及到设计模式中应遵循的设计原则,并且列出了设计模式中应当遵循的六大原则. 次篇文章主要讨论单一职责原则. 单一职责原则(SRP): 不要存在多于一个导致类变更的原因.简单的讲,就是一个类或接 ...

  5. android activity解耦,Android与设计模式:用单一职责原则为Activity解耦

    一.什么是单一职责原则单一职责原则(SRP:Single responsibility principle)又称单一功能原则,其定义为:一个类,应该只有一个可以导致变化的原因.光看概念 一.什么是单一 ...

  6. 被误解的单一职责原则 - Joe

    谷歌工程主管乔·林奇的文章,获得SOLID原则作者鲍勃大叔点赞转发的文章: 作者推荐将SRP视为DDD原则的自然结果:跨DDD限制上下文共享的模型是不安全的. 单一职责原则 (SRP) 是SOLID设 ...

  7. 设计原则-单一职责原则

    单一职责原则 文章目录 单一职责原则 概述 单一职责原则问题由来 职责如何理解呢? 什么是职责呢 ? 举例1 Rectangle 个人理解 举例2 Modem SRP核心思想 总结 参考文档 概述 在 ...

  8. 设计原则(单一职责原则 开放封闭原则 里氏替换原则 依赖倒置原则 接口隔离原则 迪米特法则)

    设计原则 单一职责原则(SRP) 从三大特性角度看原则: 应用的设计模式: 开放封闭原则(OCP) 从三大特性角度看原则: 应用的设计模式: 里氏替换原则(LSP) 从三大特性角度看原则: 应用的设计 ...

  9. 理论一:对于单一职责原则,如何判定某个的职责是否够“单一”?

    上几节课中,我们介绍了面向对象相关的知识.从今天起,我们开始学习一些经典的设计原则,其中包括,SOLID.KISS.YAGNI.DRY.LOD等. 这些设计原则,从字面上理解,都不难.你一看就感觉懂了 ...

最新文章

  1. OpenGL在图形管道中调用了什么用户模式图形驱动程序(UMD)?
  2. 取得Repeater内部控件命令名与命令参数
  3. 深入解析浏览器的幕后工作原理(四) DOM树
  4. android adapter排序,Android BindingAdapter执行顺序?
  5. IDEA中双击两下shift全局搜索怎样取消和修改
  6. boost::function_types::is_member_function_pointer用法的测试程序
  7. Solr管理页面 上
  8. ECCV2018--点云匹配
  9. php发送邮件pop3,php 发送邮件与pop3邮件登录代码
  10. 彻底解决SP2下ALEXA工具条无法显示(转)
  11. wx.getStorage异步和wx.getStorageSync同步区别
  12. 案例分享:Qt的PPT播放器
  13. 互联网流量的本质是什么?
  14. itunes显示无法更新服务器失败怎么办啊,更新iTunes出现错误 iTunes更新失败解决方案...
  15. at指令 meid_【技术分享】使用AT调制解调器命令解锁LG Android屏幕
  16. 潜入蓝翔技校二十天 探究蓝翔黑客真正的奥秘
  17. HTML5 之 Form 标签
  18. prometheus+alertmanager+webhook实现自定义监控报警系统
  19. 产生冠军(HDU1002)谢庆皇
  20. Golang实现Raft一致性算法

热门文章

  1. UITableView实现划动删除
  2. 6,ORM组件XCode(撬动千万级数据)
  3. 【数据挖掘笔记七】高级模式挖掘
  4. 数据结构源码笔记(C语言):置换-选择算法
  5. 99. 恢复二叉搜索树
  6. Windows 技术篇-设置电脑启用或禁用开机按Ctrl+Alt+Del解除锁定
  7. JVM运行时数据区概览
  8. 模拟电路技术之基础知识
  9. 第七周实践项目2.3 顺序环形队列
  10. [YTU]_2618 ( B 求类中数据成员的最大值-类模板)