spring源码设计模式分析(三)

简介: spring源码设计模式分析(三)

接着昨天的结构型设计模式写:

1、装饰器模式

意图:动态地给一个对象添加一些额外的职责,不控制原有的功能,就增加功能来说,装饰器模式.比生成子类更为灵活,而代理模式是把接口的功能给控制住了,在其他场景不会引用,只能由代理类操作。装饰者设计模式本质的类不会变,在同一个环境下可以使用两种。

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

使用场景:1、扩展一个类的功能。2、动态增加功能,动态撤销。

在Spring中是用BeanDefinitionDecorator bean定义装饰,用来将beandefinition装饰成beandefinitionHolder对象(封装了bean定义对象,bean名称 ,bean别名 ),然后用来进行bean注册使用。
提供一个规范的接口:

  1. package com.weizhaoyang.decorate;

  2. /**
  3. * 业务接口
  4. */
  5. public interface DemoService {
  6.    /**
  7.     * 业务服务demo
  8.     */
  9.    public  void  demoo();
  10. }

提供一个实现类,代码如下:

  1. package com.weizhaoyang.decorate;

  2. public class DemoServiceImpl implements  DemoService {
  3.    @Override
  4.    public void demoo() {
  5.        System.out.println("我的房子需要装修下");
  6.    }
  7. }

提供一个装饰类,而且提供一个被装饰的类,因为装饰类要依赖于主体-被装饰的类,代码如下:

  1. package com.weizhaoyang.decorate;

  2. /**
  3. * 热插拔的效果
  4. * DemoService在装饰器模式中这个类可以在任何的地方使用,不受装饰器影响
  5. * 而在代理设计模式中这个DemoService被代理类完全控制
  6. */
  7. public class DemoServiceDecorator implements  DemoService {
  8.    private DemoService demoService;
  9.    public DemoServiceDecorator(DemoService demoService){
  10.        this.demoService=demoService;
  11.    }
  12.    @Override
  13.    public void demoo() {
  14.        demoService.demoo();
  15.        System.out.println("房子已经装修成欧式风格了");
  16.    }
  17. }

给个测试类:

  1. package com.weizhaoyang.decorate;

  2. public class DemoTest {
  3.    public static void main(String[] args) {
  4.        //创建主对象
  5.        DemoService demoService=new DemoServiceImpl();
  6.        //创建装饰器
  7.        DemoServiceDecorator decorator=new DemoServiceDecorator(demoService);
  8.        decorator.demoo();
  9.    }
  10. }

运行的结果如下:

好处:原有的结构不改变,给外面的调用方来说,就是给当前的DemoService做一个封装,封装就是保护当前的对象DemoService实例,这样就会减少破坏,对扩展开放,对修改关闭如果是用继承的话将把DemoSerivice给改掉,行为被覆盖掉,动态修改父类里的方法的功能,就违背了开闭原则。

在io流中就是典型的装饰器模式来实现的,可以把上面的DemoService看作成InputStream,然而有多种InputStream,通过装饰器来装饰这个InputStram

2、责任链模式:举个生活中的例子,分工到位和去医院看病,依赖于外界的环境

也就是代替了if-else的循环,可以动态的扩展。

在spring中扩展接口是比较常用的责任链模式:

  BeanFactoryPostProcessor beanFactroy工厂后置处理器,列表循环执行

  BeanPostProcessor bean初始化后置处理器,在bean初始化前和初始化后执行,也就是进行依赖注入前后自定义处理

InstantiationAwareBeanPostProcessor bean实例化后置处理器,在bean实例化前,实例化后执行,也就是在创建bean 实例,反射创建对象实例前后进行自定义处理,同时自定义进行属性设置

DestructionAwareBeanPostProcessor bean销毁后置处理器,在bean实例销毁前进行自定义处理

SmartInstantiationAwareBeanPostProcessor 获取bean 实例的提前引用,解决循环引用的问题(框架内部调用,一般不在外部进行扩展)

      MergedBeanDefinitionPostProcessor 父bean和子bean定义自定来解决合并问题

BeanDefinitionRegistryPostProcessor bean注册后置处理器,在bean注册时候进行   BeanDefinitionRegistry注册自定义

(遵守了开闭原则,用来对扩展开放,修改关闭)

代码如下:1、创建一个病人类:

  1. package com.weizhaoyang.chain;

  2. /**
  3. * 病人类
  4. */
  5. public class BingUser {
  6.    private String name;
  7.    private String description; //病人描述

  8.    public BingUser(String description) {
  9.        this.description = description;
  10.    }

  11.    public String getName() {
  12.        return name;
  13.    }

  14.    public void setName(String name) {
  15.        this.name = name;
  16.    }

  17.    public String getDescription() {
  18.        return description;
  19.    }

  20.    public void setDescription(String description) {
  21.        this.description = description;
  22.    }
  23. }

2、提供一个医生的接口

  1. package com.weizhaoyang.chain;

  2. public interface DoctorChain {
  3.    /**
  4.     * 是否是我的病人
  5.     */
  6.    public boolean  isBingUser(BingUser bingUser);
  7.    //去医治病人
  8.    public void   doTreat(BingUser bingUser);
  9. }

3、提供治疗脚痛的医生的代码如下:

  1. package com.weizhaoyang.chain;

  2. /**
  3. * 治疗脚痛的
  4. */
  5. public class WhyDoctor implements  DoctorChain {
  6.    @Override
  7.    public boolean isBingUser(BingUser bingUser) {
  8.        if("J".equals(bingUser.getDescription())){
  9.            return true;
  10.        }
  11.        return false;
  12.    }

  13.    @Override
  14.    public void doTreat( BingUser bingUser) {
  15.        System.out.println("脚痛医生已经收到通知,开始治疗");
  16.    }
  17. }

提供治疗头痛的医生的代码如下:

  1. package com.weizhaoyang.chain;

  2. /**
  3. * 每一个医生属于一个科室,治疗头痛
  4. */
  5. public class ZhaoDoctor implements  DoctorChain {
  6.    @Override
  7.    public boolean isBingUser(BingUser bingUser) {
  8.        if("T".equals(bingUser.getDescription())){
  9.            return true;
  10.        }
  11.        return false;
  12.    }

  13.    @Override
  14.    public void doTreat( BingUser bingUser) {
  15.        System.out.println("头痛医生已经收到通知,开始治疗");
  16.    }
  17. }

4、提供一个医院的入口:

  1. package com.weizhaoyang.chain;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. /**
  5. * 医院入口类
  6. */
  7. public class DoctorDoor  {
  8.    //将病人和医生联合起来,把所有的科室注册到医院里面去
  9.    /**
  10.     * 科室集合
  11.     */
  12.    private static List<DoctorChain> chains=new ArrayList<DoctorChain>();
  13.    /**
  14.     * 添加科室责任链
  15.     */
  16.    public void  registerDoctor(DoctorChain doctorChain){
  17.        chains.add(doctorChain);
  18.    }
  19.    /**
  20.     * 添加科室责任链
  21.     */
  22.    public void  removeDoctor(DoctorChain doctorChain){
  23.        chains.remove(doctorChain);
  24.    }
  25.    /**
  26.     * 收纳病人进来
  27.     */
  28.    public  void  receiveBingUser(BingUser bingUser) throws Exception {
  29.        //1、收纳 病人成功
  30.        System.out.println("收纳病人成功");
  31.        //2、开始查找是哪一个科室进行处理
  32.        if(chains!=null &&chains.size()>0){
  33.         //3、寻找医生
  34.            for(DoctorChain doctorChain:chains){
  35.                 if(doctorChain.isBingUser(bingUser)){
  36.                     doctorChain.doTreat(bingUser);
  37.                     return;
  38.                 }
  39.            }
  40.        }else{
  41.            throw new Exception("医院并没有开科");
  42.        }
  43.    }
  44. }

写个测试类:

  1. package com.weizhaoyang.chain;

  2. public class ChainTest {
  3.    public static void main(String[] args) throws Exception {
  4.        //1、创建医院对象
  5.        DoctorDoor doctorDoor=new DoctorDoor();
  6.        //2、科室医生
  7.        DoctorChain  chain=new WhyDoctor();
  8.        DoctorChain  chain1 =new ZhaoDoctor();
  9.        doctorDoor.registerDoctor(chain);
  10.        doctorDoor.registerDoctor(chain1);
  11.        //3、需要病人
  12.        BingUser  bingUser = new BingUser("T");
  13.        doctorDoor.receiveBingUser(bingUser);
  14.    }
  15. }

运行的结果如下:

只要把责任链的设计模式,就会把springmvc的拦截器和servlet的过滤器就懂了。

3、适配器模式

本质:将不同的接口结合成相同的接口,主要用在项目上线之后,适用不用的环境中使用,mysql用的就是适配器模式,接口功能写死,新环境里面需要某个类增加新功能,同时这个功能已经存在,将这个新功能嫁接到原有功能上!

在spring中后置处理器用的是适配器模式:InstantiationAwareBeanPostProcessorAdapter bean后置处理器适配器抽象类,将所有的后置处理器接口处理成我们个性化需要的接口类型。

代码如下:1、提供一个接口:

  1. package com.weizhaoyang.adapter;

  2. public interface DemoService {
  3.    /**
  4.     * 业务服务demo
  5.     */
  6.    public void  demo(String canFlag) throws  Exception;
  7. }

2、提供一个实现类:

  1. package com.weizhaoyang.adapter;
  2. /**
  3. *这个已经是具体的环境
  4. * 统一的入口传不同的参数调用不同的方法,对参数没有修改,通过参数适配,适配不同的接口
  5. * 不影响原有的接口
  6. */
  7. public class DemoServiceImpl implements  DemoService {
  8.    private DemoServiceAdapter  demoServiceAdapter;
  9.    @Override
  10.    public void demo(String canFlag) throws Exception {
  11.        if("code".equals(canFlag)){
  12.            System.out.println("我本来有写代码的能力");
  13.        }else if("fly".equals(canFlag)){
  14.            //传fly就进行适配,如果有多个适配就写多个适配接口
  15.            demoServiceAdapter = new DemoServiceAdapter();
  16.            demoServiceAdapter.demo(canFlag);
  17.        }else{
  18.            throw new Exception("能力不够");
  19.        }
  20.    }
  21. }

3、提供一个飞的接口:

  1. package com.weizhaoyang.adapter;

  2. public interface FlyService {
  3.  public  void fly();
  4. }

4、提供一个实现类

  1. package com.weizhaoyang.adapter;

  2. public class FlyServiceImpl implements  FlyService {
  3.    @Override
  4.    public void fly() {
  5.        System.out.println("我能飞");
  6.    }
  7. }

5、提供一个是适配器的类:

  1. package com.weizhaoyang.adapter;

  2. /**
  3. * 适配谁就以谁为主,适配DemoService
  4. * 适配器一定要去实现主接口
  5. * 在类里面加一个适配器类就能够适配
  6. * 具体的环境,适配谁就以谁为主
  7. * 如果不用设计模式的话在DemoService接口里面添加新功能的话,会有代码冗余。
  8. * 适配器需要实现主接口
  9. */
  10. public class DemoServiceAdapter implements  DemoService{
  11.    //依赖飞接口
  12.    private FlyService flyService;
  13.    public DemoServiceAdapter(){
  14.        this.flyService= new FlyServiceImpl();
  15.    }
  16.    //fly的方法和demo的方法是不兼容的同时方法参数不一样,方法名不一样,这个时候接口demo需要适配。
  17.    //如果方法名相同,这个时候不需要适配的
  18.    //适配器用飞和code进行解耦
  19.    public void demo(String canFlag) {
  20.        if("fly".equals(canFlag)){
  21.            flyService.fly();
  22.        }
  23.    }
  24. }

6、提供一个测试类:

  1. package com.weizhaoyang.adapter;

  2. public class DemoTest {
  3.    public static void main(String[] args) throws Exception {
  4.        DemoService demoService = new DemoServiceImpl();
  5.        demoService.demo("code");
  6.        demoService.demo("fly");
  7.    }
  8. }

运行的结果如下:

总结:装饰器的话,另外一个接口不存在,而适配器模式是两个接口存在,谁需要改变,就适配谁。对接口可以扩展,对调用不要修改,通一个过主体的参数返回一个新的功能

相关文章
|
30天前
|
Java 调度 开发者
spring的@Scheduled()有几种定时模式?
【10月更文挑战第12天】spring的@Scheduled()有几种定时模式?
71 1
|
1月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
404 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
1月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
167 2
|
2月前
|
设计模式 Java Spring
spring源码设计模式分析(五)-策略模式
spring源码设计模式分析(五)-策略模式
|
2月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
102 5
|
2月前
|
消息中间件 设计模式 缓存
spring源码设计模式分析(四)-观察者模式
spring源码设计模式分析(四)-观察者模式
|
2月前
|
设计模式 Java Spring
spring源码设计模式分析(六)-模板方法模式
spring源码设计模式分析(六)-模板方法模式
|
2月前
|
XML 存储 Java
Spring-源码深入分析(二)
Spring-源码深入分析(二)
|
2月前
|
XML 设计模式 Java
Spring-源码深入分析(一)
Spring-源码深入分析(一)
|
Java 应用服务中间件 数据库连接
Spring全家桶之Spring篇深度分析(一)
Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
Spring全家桶之Spring篇深度分析(一)