1个类只负责1个功能领域中的相应职责,或可以定义为:就1个类而言,应当只有1个引发它变化的缘由。
亚当·斯密曾就制针业做过1个分工产生效力的例子。对1个没有受过相应训练,又不知道怎样使用这类职业机械的工人来说,即便他全力以赴地工作,或许1天连1根针也生产不出来,固然更生产不出20根针了。但是,如果把这个行业分成各种专门的组织,再把这类组织分成许多个部门,其中大部份部门也一样分为专门的组织。把制针分为18种不同工序,这18种不同操作由18个不同工人来担负。那末,虽然他们的机器装备都很差,但他们尽力工作,1天也能生产12磅针。每磅中等型号针有4000根,按这个数字计算,10多个人每天就能够制造48000根针,而每一个人每天能制造4800根针。如果他们各自独立地工作,谁也不专学做1种专门的业务,那末他们当中不管是谁都绝不可能1天制造20根针,或许连1根针也制造不出来。这就是企业管理中的分工,在面向对象的设计里,叫做单1职责原则(Single Pesponsibility Principle,SRP)。
在《敏捷软件开发》中,把“职责”定义为“变化的缘由”,也就是说,就1个类而言,应当只有1个引发它变化的缘由。说的简单点就是怎样设计1个类和类的方法界定问题。这类问题很普遍,比如在MVC框架中,很多人会有这样的疑惑,对表单插入数据库字段过滤与安全检查应当是放在control层处理还是model层处理,这类问题可以归到单1职责的范围。
单1职责有两个含义:1个是避免相同的职责分散到不同的类中,另外一个是避免1个类承当太多职责。
可以减少类之间的耦合。
如果减少类之间的耦合,当需求变化时,只修改1个类,从而也就隔离了变化;如果1个类有多个不同职责,它们耦合在1起,当1个职责产生变化时,可能会影响其他职责。
提高类的复用性
修理电脑比修理电视机简单多了。主要缘由就在于电视机各个部件之间的耦合性太高,而电脑则不同,电脑的内存、硬盘、声卡、网卡、键盘灯部件都可以很容易地单独拆卸和组装。某个部件坏了,换上新的便可。
上面的例子就体现了单1职责的优势。由于使用了单1职责,使得“组件”可以方便地“拆卸”和“组装”。
不遵照SRP会影响对该类的复用性。当只需要复用该类的某1个职责时,由于它和其他的职责耦合在1起,也就很难分离出。
有的。以数据持久层为例,所谓的数据持久层主要指的是数据库操作,固然,还包括缓存管理等。以数据库操作为例,如果是1个复杂的系统,那末便可能触及多种数据库的相互读写等,这时候就需要数据持久层支持多种数据库。应当怎样做?定义多个数据库操作类?你的想法已很接近了,再进1步,就是使用工厂模式。
工厂模式(Factory)允许你在代码履行时实例化对象。它之所以被称为工厂模式是由于它负责“生产”对象。以数据库为例,工厂需要的就是根据不同的参数,生成不同的实例化对象。最简单的工厂就是根据传入的类型名实例化对象,如传入MySQL,就调用MySQL的类并实例化,如果是SQLite,则调用SQLite的类并实例化,乃至可以处理TXT、Excel等“类数据库”。工厂类也就是这样的1个类,它只负责生产对象,而不负责对象的具体内容。
设计模式里面的命令模式也是SRP的体现,命令模式分离“命令的要求者”和“命令的实现者”方面的职责。举1个很好理解的例子,就是你去餐馆吃饭,餐馆存在顾客、服务员、厨师3个角色。作为顾客,你只要列出菜单,传给服务员,由服务员通知厨师去实现。作为服务员,只需要调用准备饭菜这个方法(对厨师大喊“该炒菜了”),厨师听到要炒菜的要求,就立即去做饭。在这里,命令的要求和实现就完成了解耦。
在设计模式方面,不但以上这两种体现了SRP,还有别的(比如代理模式)也体现了SRP。SRP不只是对类设计成心义,对以模块、子系统为单位的系统架构设计一样成心义。
模块、子系统也应当唯一1个引发它变化的缘由,如MVC所提倡的各个层之间的相互分离其实就是SRP在系统整体设计中的利用。
根据业务流程,把业务对象提炼出来。如果业务流层的链路太复杂,就把这个业务对象分离为多个单1业务对象。当业务链标准化后,对业务对象的内部情况做进1步处理。把第1次标准化视为最高层抽象,第2次视为次高层抽象,以此类推,直到“恰如其分”的设计层次。
职责的分类需要注意。有业务职责,还要有脱离业务的抽象职责,从认识业务到抽象算法是1个层层递进的进程。就好比命令模式中的顾客,服务员和厨师的职责,作为老板(即设计师)的你需要计划好各自的职责范围,既要避免越俎代庖,也要避免相互推委。