面向对象设计原则(一):单一职责原则(SRP)

面向对象设计原则(一):单一职责原则(SRP)

       单一职责原则(Single responsibility principle,SRP)是面向对象设计(OOD)中比较重要、常见的一种,下面来总结单一职责原则的知识点,包括:

       1、什么是单一职责原则、什么是职责?

       2、为什么需要遵守单一职责原则,违反单一职责有什么坏处?

       3、单一职责原则需要注意什么?

       4、单一职责原则的应用案例。

1、什么是单一职责原则(SRP)

1-1、原则的定义

       单一职责原则(Single responsibility principle,SRP)可以表示为:

      一个类应该仅有一个引起它变化的原因。

1-2、什么是职责

       职责定义为:

      变化的原因"(a reason for change)。

      如果你能够想到多于一个的动机去改变类,那么这个类就具有多于一个的职责。

       这条原则曾经被认为与内聚性(cohesion)相关。内聚性可以定义为:一个模块的组合元素之间的功能相关性。即对一个类来说,这个类是否只专心做一件事。

       Robert Cecil Martin("Bob"大叔)把职责定义为变化的原因,更能表达出该原则的特性。

2、为什么需要单一职责原则

       即单一职责原则能带来什么,可以从下面两个问题来描述。

2-1、为何要把这两个职责分离到单独的类中呢?

       因为每个职责都是一个变化的原因。当需求变化时,该变化会反映到类的职责的变化。

       如果一个类承担了多于一个的职责,那么引起它变化的原因就会有多个。

       而单一职责原则正是反映了《代码大全》中所说的:软件的首要技术使命--管理复杂度,而找出容易变化改变的区域,隔离变化,就是一种很好的管理复杂度的启发方法。

2-2、违反单一职责原则有什么坏处?

       如果一个类承担的职责过多,等于把这些职责耦合在了一起;一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。

       这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。

3、单一职责原则需要注意什么

3-1、一个类实现多个接口的情况

      一个类可能需要实现多个接口,这会产生职责耦合;

      但多个接口就是一种解耦表现,一个接口相关职责的变化一般不会引起其他接口的变化。

      后面我们会介绍到接口隔离原则(ISP):

      不应该强迫客户依赖于它们不用的方法。

      其中一种方法就是使用多重继承分离接口,即一个类实现了多个接口,分别提供给不同客户的接口只有该客户需要的操作。

      更多信息可以参考:

《面向对象设计原则(四):接口隔离原则(ISP)》

3-2、不必分离两个总是同时变化的职责

      如果应用程序的变化总是导致这两方面职责同时变化,那么就不必分离他们。

      实际上,分离他们就会具有不必要的复杂性。

3-3、不要预先设计

      仅当变化发生时,针对该变化的设计才具有实际意义。

      如果没有前兆,那么应用SRP或者任何其他原则都是不明智的。

4、单一职责原则的应用

      常见的容易变化的区域包括:业务规则、对硬件的依赖性、输入和输出、非标准的语言特性、困难的设计区域和构建区域。

      例如:

      通常,业务规则和对于持久化的控制这两个职责不应该混合在一起。

      因为业务规则往往会频繁地变化,而持久化的方式却不会如此频繁地变化,并且变化的原因也是完全不同的。

      这在平时开发中是很常见的分层应用,如用户管理的业务规则为增/删/改/查对应UserManageService接口:

public interface UserManageService {    

        public ResultMsg create(Integer tokenId, String sign, User user);

        public ResultMsg delete(Integer tokenId, String sign, Integer userId);

        public ResultMsg update(Integer tokenId, String sign, User user);

        public ResultMsg get(Integer tokenId, String sign, Integer userId);

}

      而用户管理的持久化也为增/删/改/查对应UserDao接口:

public interface UserDao{

        public boolean add(User user);

        public boolean delete( Integer userId);

        public boolean update(User user);

        public User get(Integer userId);

}

      实现UserManageService接口的UserManageServiceImpl类中处理完业务后,判断是否需要调用UserDao接口的相应实现,一些代码如下:

@Service("userManageService")

public class UserManageServiceImpl implements UserManageService {

    @Resource(name="UserDaoImpl")

    private UserDao<User> userDao;

    ……

    @Override

    public ResultMsg create(Integer tokenId, String sign, User user) {

        …..

        //处理完业务后,判断是否需要调用UserDao接口的相应实现

        userDao.add(user);

        ……

     }

     …..

}

      另外,一般应该尽早分离两个职责,后期才发现的可以考虑使用FACADE(外观)、PROXY(代理)模式对设计进行重构,分离两个职责。

5、总结

       单一职责原则:

      一个类应该仅有一个引起它变化的原因。

     即:

管理复杂度,找出容易变化/改变的区域,隔离变化。

      单一职责原则是最简单的原则之一,也是最难正确运用的原则之一,因为我们很容易把职责结合一起。

      软件设计很重要的工作就是发现职责并把那些职责相互分离,我们平时或多或少的都使用到单一职责原则,如果开发中能关注到就更好了。


      更多SRP的信息请参考:

      维基百科"Single responsibility principle"(可以看里面给出的参考资料)


      到这里,我们对单一职责原则有了一个大体的了解,还需要平时开发中多注意,后面我们将了解其他的面向对象设计原则......


【参考资料】

1、《敏捷软件开发:原则、模式与实践》第8章 单一职责原则(SRP)

2、维基百科"Single responsibility principle":https://en.wikipedia.org/wiki/Single_responsibility_principle

3、《代码大全》第二版 第5章 软件构件中的设计

4、《大话设计模式》第3章

猜你喜欢

转载自blog.csdn.net/tjiyu/article/details/57079598