设计说明

观察者模式



    <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>30.0-jre</version>
        </dependency>



定义

登陆注册应该是最常见的业务场景了。就拿注册来说事,我们经常会遇到类似的场景,就是用户注册成功后,我们给用户发一条消息,又或者发个邮件等等,因此经常有如下的代码:

void register(User user){
  insertRegisterUser(user);
  sendIMMessage();
  sendEmail();
}

这块代码会有什么问题呢? 如果产品又加需求:现在注册成功的用户,再给用户发一条短信通知。于是你又得改register方法的代码了。。。这是不是违反了开闭原则啦。

并且,如果调发短信的接口失败了,是不是又影响到用户注册了?!这时候,是不是得加个异步方法给通知消息才好。。。
实际上,我们可以使用观察者模式优化。




具体代码

image-20221201104921264



单例模式



如何连接不同的数据库呢?我们采用的策略是:设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址(<poolName.url>)﹑用户名(<poolName.user>)﹑密码(<poolName.password>)等信息。如tx.url=172.21.15.123:5000/tx_it,tx.user=yang,tx.password=yang321。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。



连接池管理类是连接池类的外覆类(wrapper),符合单例模式,即系统中只能有一个连接池管理类的实例。其主要用于对多个连接池对象的管理,具有以下功能:①装载并注册特定数据库的JDBC驱动程序;②根据属性文件给定的信息,创建连接池对象;③为方便管理多个连接池对象,为每一个连接池对象取一个名字,实现连接池名字与其实例之间的映射;④跟踪客户使用连接情况,以便需要是关闭连接释放资源。连接池管理类的引入主要是为了方便对多个连接池的使用和管理,如系统需要连接不同的数据库,或连接相同的数据库但由于安全性问题,需要不同的用户使用不同的名称和密码。



Springboot 使用 druid 连接池,yml 配置,然后添加配置类即可

spring:
  datasource:
    druid:
      url: jdbc:mysql://43.138.27.94:3306/dump?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&verifyServerCertificate=false&useSSL=false
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: mall-12345
      initial-size: 10
      max-active: 50
      min-idle: 10
      max-wait: 60000
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      validation-query: SELECT 1 FROM DUAL
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      time-between-eviction-runs-millis: 60000
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: false
      filter:
        stat:
          enabled: false



@Configuration
public class DruidConfig {

    /*
       将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
}



责任链模式



责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

业务场景



一般有参数非空校验、安全校验、黑名单校验、规则拦截等等。很多伙伴会使用异常来实现,如果后续逻辑越来越复杂的话,会出现一些问题:如异常只能返回异常信息,不能返回更多的字段,这时候需要自定义异常类。
并且,阿里开发手册规定:禁止用异常做逻辑判断。




定义

责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。



使用

责任链模式怎么使用呢?

一个接口或者抽象类
每个对象差异化处理
对象链(数组)初始化(连起来)



具体参考代码:

image-20221201105839433



策略模式



应用场景

文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:

if(type=="A"){
   //按照A格式解析
 
}else if(type=="B"){
    //按B格式解析
}else{
    //按照默认格式解析
}



这个代码可能会存在哪些问题呢?

如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低。
如果你需要接入一种新的解析类型,那只能在原有代码上修改。

说得专业一点的话,就是以上代码,违背了面向对象编程的开闭原则以及单一原则。

开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
单一原则(规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。

如果你的代码就是酱紫:有多个if...else等条件分支,并且每个条件分支,可以封装起来替换的,我们就可以使用策略模式来优化。


实现

一个接口或者抽象类,里面两个方法(一个方法匹配类型,一个可替换的逻辑实现方法)
不同策略的差异化实现(就是说,不同策略的实现类)
使用策略模式



具体代码

image-20221201111326630




工厂模式


🍾 这个工厂模式和策略模式一起使用的,具体参考上面的策略模式,定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。


场景

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

工厂模式一般配合策略模式一起使用。用来去优化大量的if...else...或switch...case...条件语句。

定义工厂模式也是比较简单的:

一个工厂接口,提供一个创建不同对象的方法。
其子类实现工厂接口,构造不同对象
使用工厂模式



工厂方法的接口:

image-20221201111557123

posted @ 2022-12-01 11:45  雨同我  阅读(174)  评论(0编辑  收藏  举报