OO案例分析—单一职责原则
定义:
单一职责(SRP,Single Responsibility Principle)强调的是职责的分离,在某种程度上对职责的理解,构成了不同类之间耦合关系的设计关键,因此单一职责原则或多或少成为设计过程中一个必须考虑的基础性原则。
核心思想:
一个类,最好只做一件事情,只有一个引起它变化的原因。
单一职责原则可以看做是低耦合,高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。职责过多,可能引起它变化的原因就越多,这将导致依赖,相互之间就产生影响,从而极大的损伤其内聚性和耦合性。单一职责,通常意味着单一的功能,因此不要为类实现过多的功能点,以保证实体只有一个引起它变化的原因。
重构方法:
对于违反这一个原则的类应该进行重构,例如以Façade模式或Proxy模式分离职责,通过基本方法Extract Interface ,Extract Class 和Extract Method进行梳理。
案例分析:
MIS 系统中根据不同的权限进行数据增删改查的系统比比皆是,然而这正是一个比较常见的一种需求场景,先看设计图:
图2-1违法SRP的设计
以上设计,DBManager类将对数据库的操作和用户权限的判断封装在一个类中去实现,看小段代码:
public void Add() { if(GetPermission(id) == "CanAdd") { Insert();// 可以添加数据 ,数据库操作逻辑代码 } }
现在GetPermission(string Id)权限设置规则发生变化, 那么Insert() 数据库操作逻辑全部要修改,必须首先将这种代码扫地清理掉。
按照单一职责原则,一个类只有一个引起它变化的原因,下面我们选择合适的方法进行重构有缺陷的设计,在此我们使用Proxy模式来解决类太累的问题,重构之后的设计图:
图2-2职责分离的设计
以Proxy模式重构之后,有效的实现了职责分离,DBManager专注于执行数据库的操作,下面来看修改之后的代码:
public class DBManager:IDAO { public void Add() { throw new NotImplementedException(); } public void View() { throw new NotImplementedException(); } public void Delete() { throw new NotImplementedException(); } }
而DBManagerProxy只需关注于数据库逻辑的操作:
public class DBManagerProxy:IDAO { private IDAO dbdaoInstance; public DBManagerProxy(IDAO dbdao) { dbdaoInstance = dbdao; } string GetParmession(string id) { // 判断逻辑 return "Add"; } public void Add() { if (GetParmession("Add")=="ADD") { // 权限操作 } } public void View() { throw new NotImplementedException(); } public void Delete() { throw new NotImplementedException(); } }
小结:
在实例中IDAO 体现了设计模式中的重要原则:依赖倒置原则(DIP),通过DBManagerProxy代理类实现了职责分离,DBManager仅有一个引起变化的原因,就是数据操作的需求变更,而权限的变更和修改不对DBManager 造成任何影响,体现了单一职责原则。
适用场景:
一个类只有一个引起它变化的原因,否则就应当考虑重构。
SRP由引起变化的原因决定,而不由功能决定。虽然职责常常引起变化的轴线,但有时就未必,应该适当考虑。
可以通过Facade模式或Proxy模式进行职责分离。
个人心得和大家共勉:
在实际的项目过程中间要不断的去重构自己的代码,平时多看好书,不过现在好书不多(市场上也就那么几本),要多去思考书中作者写的每一个示例,举一反三,会逐步的提高自己的设计能力和分析能力。