第2章 单一指责原则(SRP)

前端之家收集整理的这篇文章主要介绍了第2章 单一指责原则(SRP)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一、单一指责原则(single responsibility principle,SRP)

什么是类的职责?以及怎么划分类的职责

1、单一指责的定义:应该有且仅有一个原因引起类的变更。 变化的原因就是所说的"职责"。

2、如果一个类有多个引起它变化的原因,也就意味着这个类有多个职责。即把多个职责耦合在一起了。

3、“职责”的粒度不好量化。实际开发中,这个原则最容易违反

二、单一指责的优点

1、类的复杂性降低,一个类负责一项职责,实现什么职责都有清晰明确的定义。

2、提高类的可读性和可维护性

3、变化引起的风险降低,变化是必然的,如果接口的单一指责做得好,一个接口的修改只会对相应的实现类有影响,对其他接口无影

响,对系统的扩展性、维护性有好处。

三、实例分析

1、用户管理类的实现

只要做过项目,肯定接触过用户、机构、角色管理这些模块,基本上使用RBAC模型(基于角色的访问控制,通过分配和取消角色来完

用户权限的授予和取消,是动作主体 用户 与 资源的行为 权限 分离),确实是很好的解决方法

(1)、臃肿的接口设计

用户管理类,通过一个接口实现。

接口设计的问题:用户属性用户的行为没有分开,严重的错误!我们应该把用户的信息抽取成一个BO(Business Object业务对

象),把行为抽取成一个Biz(Business Logic业务逻辑),按照这个思路进行接口设计:

(2)、职责分离

为什么要把一个接口拆分成两个呢?实际使用中,我们更倾向于使用两个类或接口,一个是IUserBO,一个是IUserBiz。就是依赖单

一指责原则。 java中实现可以是依赖的关系,但是C++中实现是关联 或者 聚合应该都可以。

(3)根据类图代码实现(如果能清晰的看懂类图,代码实现起来还是很简单的)

@H_404_106@#include <iostream> #include <string> using namespace std; //业务对象抽象类 class IUserBO { public: virtual void setUserID(string userID) = 0; virtual string getUserID() = 0; virtual void setPassword(string password) = 0; virtual string getPassword() = 0; virtual void setUserName(string userName) = 0; virtual string getUsername() = 0; }; class UserBO : public IUserBO { private: string userID; string userName; string passWD; public: UserBO(string userid,string username,string passwd) { userID = userid; userName = username; passWD = passwd; } UserBO(const UserBO& object) { userID = object.userID; userName = object.userName; passWD = object.passWD; } UserBO& operator = (const UserBO& object) { if (this != &object) { userID = object.userID; userName = object.userName; passWD = object.passWD; } return *this; } void setUserID(string userID) { this->userID = userID; } string getUserID() { return userID; } void setPassword(string password) { this->passWD = password; } string getPassword() { return passWD; } void setUserName(string userName) { this->userName = userName; } string getUsername() { return userName; } }; //业务逻辑抽象类 class IUserBiz { public: virtual bool changePassword(string passwd) = 0; virtual bool deleteUser(string username) = 0; virtual bool addOrg(int orgID) = 0; virtual bool addRole(int roleID) = 0; }; class UserBiz : public IUserBiz { private: IUserBO* userBO; public: UserBiz(IUserBO* object) { userBO = object; } bool changePassword(string passwd) { bool rtn = true; if (userBO->getPassword() != passwd) { userBO->setPassword(passwd); cout << "修改密码成功!" << endl; } else { rtn = false; } return rtn; } bool deleteUser(string username) { bool rtn = true; if (userBO->getUsername() != username) { rtn = false; } else { cout << "删除用户成功!" << endl; } return rtn; } bool addOrg(int orgID) { cout << "自行实现!" << endl; return true; } bool addRole(int roleID) { cout << "自行实现!" << endl; return true; } }; int main(void) { UserBO* userBO = new UserBO("1","spach","lixin101357"); //用户逻辑类对象可以对这个进行处理 IUserBiz* userbiz = new UserBiz(userBO); if (userbiz->changePassword("helloworld")) { cout << userBO->getPassword() << endl; } cin.get(); return 0; }

2、电话类图

电话通话的时候有四个过程:拨号、通话、回应、挂机,我们实现一个接口:类图如下所示:请忽视图是截过来的,重点是分析

拨通电话、通过、通话完毕挂电话

单一职责要求一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责,负责一件事情,貌似上面的类不是这样的。

Iphone接口两个职责:协议管理、数据传送。dial()和hangup()实现的事协议管理,分别负责拨号接通和挂机;chat()实现的是数据传送。

我们可以这样考虑问题:协议接通的变化会引起接口或类的变化,数据传送也会引起类或接口的变化。两个原因都引起了类的变化。但是两个职责会相

互影响吗?不会的。

类图上的IPhone接口包括两个职责,而且职责的变化不会相互影响,那就可以考虑两个接口,类图如下所示:


一个手机类要把ConnectionManager和DataTransfer组合在一块才能使用。组合是强耦合关系,共同的生命周期,这样的强耦合关系还不如使用接口实

现的方式,增加类的复杂性,多了两个类,修改类图如下:

一个类实现两个接口,把两个职责融合在一个类中。你会觉得这个Phone有两个原因引起变化,是的,但是别忘了我们是面向接口编程的,对外公布的

是接口而不是实现类。而且,如果真的要实现类的单一指责原则,必须使用上面的组合模式,会引起类间耦合过重、类数量增加等问题,人为增加设计

的复杂性。

四、总结

1、单一指责原则适用于类、接口,同时也适用于方法。一个方法尽可能做一件事情。

方法职责不清晰,不单一,不要让别人猜测这个方法是用来处理什么逻辑的。

2、建议接口一定要做到单一指责,类的设计尽量做到只有一个原因引起变化。

原文链接:https://www.f2er.com/javaschema/283585.html

猜你在找的设计模式相关文章