设计模式 - 六大设计原则之SRP(单一职责)

2023-02-23 19:21:43 浏览数 (1)

文章目录

  • 概述
  • Case
  • Bad Impl
  • Better Impl
    • 1. 定义接口
    • 2. 职责分离-多种实现类
    • 3. 单元测试
  • 小结

概述

单一职责原则(Single Responsibility Principle, SRP)又称单一功能原则,是面向对象的五个基本原则(SOLID)之一。 它规定一个类应该只有一个发生变化的原因。

在程序设计领域,SOLID 是由罗伯特·C·马丁在 21 世纪早期引入的记忆术首字母缩略字,指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,能够使得一个程序员开发一个容易进行维护和扩展的系统变得更加可能。

SOLID 是以下五个单词的缩写:

Single Responsibility Principle(单一职责原则) Open Closed Principle(开闭原则) Liskov Substitution Principle(里氏替换原则) Interface Segregation Principle(接口隔离原则) Dependency Inversion Principle(依赖倒置原则)


我们设想一下: 加入需要开发的功能需求不是一次性的,且随着业务的发展而不断变化,那么当一个Class类负责的功能超过两个及以上职责时, 就在需求的不断迭代、实现类持续扩张的情况下,久而久之就会出现代码难以维护、扩展困难、测试难度大、上线风险高等诸多问题。

所谓的职责就是指类变化的原因,也就是业务需求。 如果一个类有多于一个的原因被改变,那么这个类就有超过两个及以上的职责。 而单一直接就是约定一个类应该有且仅有一个改变的原因。


Case

  • 访客用户, xxxx
  • 普通会员, xxxx
  • VIP会员, xxxx

Bad Impl

代码语言:javascript复制
public class VideoUserService {

    public void serveGrade(String userType){
        if ("VIP用户".equals(userType)){
            System.out.println("VIP用户,视频1080P蓝光");
        } else if ("普通用户".equals(userType)){
            System.out.println("普通用户,视频720P超清");
        } else if ("访客用户".equals(userType)){
            System.out.println("访客用户,视频480P高清");
        }
    }

}

可以看到实现非常简单,暂时也不会出现什么问题。 但这一个类里包含多个不同的行为 ,也就是多种用户职责。 如果在这样的类上进行功能扩展或者逻辑修改,就会显得非常的臃肿。

接下来我们看看如何调用处理,写个单测

代码语言:javascript复制
    @Test
    public void test_serveGrade(){
        VideoUserService service = new VideoUserService();
        service.serveGrade("VIP用户");
        service.serveGrade("普通用户");
        service.serveGrade("访客用户");
    }

因为上面的实现方式是在VideoUserService#serveGrade 通过if else实现的业务逻辑, 所以在调用方法是所有的职责用户都使用一个方法实现,作为程序的调用入口。

简单的需求没啥问题,频繁变化的需求带来的代码修改都有可能影响其他逻辑,给整个接口服务带来不可控的风险。


Better Impl

为了满足不断迭代的需求, 就不能使用一个类把所有的职责行为混为一谈,而是应该提供一个上层的接口,对不同的差异化的用户给出单独的实现类,拆分各自的职责边界。

1. 定义接口

代码语言:javascript复制
public interface IVideoUserService {

    // 视频清晰级别;480P、720P、1080P
    void definition();

    // 广告播放方式;无广告、有广告
    void advertisement();

}

定义出上层接口IVideoUserService ,统一定义需要实现的功能: 视频清晰级别接口、广告播放方式接口 。 三种不同类型的用户就可以分别实现自己的服务类,做到职责统一。


2. 职责分离-多种实现类

【访问客户】

代码语言:javascript复制
public class GuestVideoUserService implements IVideoUserService {
    
    public void definition() {
        System.out.println("访客用户,视频480P高清");
    }

    public void advertisement() {
        System.out.println("访客用户,视频有广告");
    }

}

【普通会员】

代码语言:javascript复制
public class OrdinaryVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("普通用户,视频720P超清");
    }

    public void advertisement() {
        System.out.println("普通用户,视频有广告");
    }

}

【VIP】

代码语言:javascript复制
public class VipVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("VIP用户,视频1080P蓝光");
    }

    public void advertisement() {
        System.out.println("VIP用户,视频无广告");
    }

}

综上,每种用户对应的服务职责都有各自的类负责实现,不会相互干扰。 当某一类需要添加新的运营规则时,操作起来也比较简单。


3. 单元测试

代码语言:javascript复制
  @Test
    public void test_VideoUserService(){

        IVideoUserService guest = new GuestVideoUserService();
        guest.definition();
        guest.advertisement();

        IVideoUserService ordinary = new OrdinaryVideoUserService();
        ordinary.definition();
        ordinary.advertisement();

        IVideoUserService vip = new VipVideoUserService();
        vip.definition();
        vip.advertisement();

    }

可以看到,利用单一原则优化后,每个类都只负责自己的用户行为。 后续无论是扩展还是修改仅需要修改某个用户行为类即可。


小结

在项目开中,尽可能保证接口的定义、类的实现、方法开发保持单一的职责,对项目的迭代和维护非常有帮助 .

0 人点赞