常用设计模式

目录

目录

一、设计模式简介

1、设计模式是什么

2、设计模式的种类

3、设计模式的六大原则

二、创建型模式

1、工厂模式

2、抽象工厂模式

3、单例模式

3.1、单例模式的优缺

3.2、单例创建方式

3.3、饿汉式

3.4、懒汉式

3.4、静态内部类式

3.5、枚举单例

3.6、双检锁式

三、行为型模式

3.1、责任链模式

3.1.1、实现流程



一、设计模式简介

1、设计模式是什么

  • 是软件开发人员在软件开发过程中面临的一般问题的解决方案。
  • 是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
  • 是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。
  • 是为了重用代码、让代码更容易被他人理解、保证代码可靠性。

2、设计模式的种类

我们常说的设计模式有23种分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。除此之外还有另一类设计模式,就是J2EE 设计模式,有8种。

 ​​​​常规23种设计模式:常用设计模式_第1张图片

 J2EE设计模式:特别关注表示层。这些模式是由 Sun Java Center 鉴定的。

  • MVC 模式(MVC Pattern)
  • 业务代表模式(Business Delegate Pattern)
  • 组合实体模式(Composite Entity Pattern)
  • 数据访问对象模式(Data Access Object Pattern)
  • 前端控制器模式(Front Controller Pattern)
  • 拦截过滤器模式(Intercepting Filter Pattern)
  • 服务定位器模式(Service Locator Pattern)
  • 传输对象模式(Transfer Object Pattern)

并发型模式(Concurrency Patterns):关注多线程环境下的并发操作和资源共享问题。这些模式帮助解决线程安全、同步和协调等并发编程的挑战。

  • 保护性暂停模式(Guarded Suspension Pattern)
  • 读写锁模式(Read-Write Lock Pattern)
  • 生产者消费者模式(Producer-Consumer Pattern)
  • 管程模式(Monitor Pattern)
  • 同步模式(Synchronization Pattern)

3、设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

5、迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

二、创建型模式

1、工厂模式

        工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法。

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

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

1.1、Spring开发中的工厂设计模式

(1)Spring IOC

  • 看过Spring源码就知道,在Spring IOC容器创建bean的过程是使用了工厂设计模式
  • Spring中无论是通过xml配置还是通过配置类还是注解进行创建bean,大部分都是通过简单工厂来进行创建的。
  • 当容器拿到了beanName和class类型后,动态的通过反射创建具体的某个对象,最后将创建的对象放到Map中。

(2)为什么Spring IOC要使用工厂设计模式创建Bean呢

  • 在实际开发中,如果我们A对象调用B,B调用C,C调用D的话我们程序的耦合性就会变高。(耦合大致分为类与类之间的依赖,方法与方法之间的依赖。)
  • 在很久以前的三层架构编程时,都是控制层调用业务层,业务层调用数据访问层时,都是是直接new对象,耦合性大大提升,代码重复量很高,对象满天飞
  • 为了避免这种情况,Spring使用工厂模式编程,写一个工厂,由工厂创建Bean,以后我们如果要对象就直接管工厂要就可以,剩下的事情不归我们管了。Spring IOC容器的工厂中有个静态的Map集合,是为了让工厂符合单例设计模式,即每个对象只生产一次,生产出对象后就存入到Map集合中,保证了实例不会重复影响程序效率。

1.2、简单工厂

(1)什么是简单工厂模式

  • 简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。

(2)代码演示

步骤1:创建一个接口:

public interface Shape {
   void draw();
}

步骤2:创建两个实现接口的实体类

public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

public class Circle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

步骤3:创建一个工厂,生成基于给定信息的实体类的对象。

public class ShapeFactory {
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      }
      return null;
   }
}

步骤4:使用该工厂,通过传递类型信息来获取实体类的对象。

public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
 
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
      //调用 Rectangle 的 draw 方法
      shape2.draw();
   }
}

步骤5:程序输出结果。

Inside Circle::draw() method.
Inside Rectangle::draw() method.

1.3、工厂方法模式

(1)什么是工厂方法模式

        工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节

(2)代码演示

  1. 创建工厂
public interface Car {
	public void run();
}

      2. 创建工厂方法调用接口(所有的产品需要new出来必须继承他来实现方法)

public interface CarFactory {
	Car createCar();
}

    3. 创建工厂的产品(奥迪)

public class AoDi implements Car {
	public void run() {
		System.out.println("我是奥迪汽车..");
	}
}

    4. 创建工厂另外一种产品(宝马)

public class Bmw implements Car {
	public void run() {
		System.out.println("我是宝马汽车...");
	}
}

   5.创建工厂方法调用接口的实例(奥迪)

public class AoDiFactory implements CarFactory {
	public Car createCar() {
		return new AoDi();
	}
}

  6. 创建工厂方法调用接口的实例(宝马)

public class BmwFactory implements CarFactory {
	public Car createCar() {
		return new Bmw();
	}
}

  7. 演示创建工厂的具体实例

public class Client {
	public static void main(String[] args) {
		Car aodi = new AoDiFactory().createCar();
		Car jili = new BmwFactory().createCar();
		aodi.run();
		jili.run();
	}
}

2、抽象工厂模式

        抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。其他工厂负责创建具体的产品。该超级工厂又称为其他工厂的工厂。

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

主要解决:主要解决接口选择的问题。

何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

抽象工厂模式包含的角色:

  • 抽象工厂:声明一组用于创建一族产品的方法,每个方法对应一种对象;在抽象工厂中声明了多个工厂方法, 用于创建不同类型的对象, 抽象工厂可以是接口, 也可以是抽象类或者具体类,具体实现可参考上例中的ShapeFactory;
  • 具体工厂:具体工厂实现了抽象工厂,每个工厂方法返回一个具体对象,一个具体工厂所创建的具体对象构成一个族。具体实现可参考上例中的RedShapeFactory;
  • 抽象类接口:提供一组所有类都具有的业务方法。
  • 抽象类:用于实现抽象接口所定义的业务方法,但是该角色对于抽象接口定义的方法只做抽象实现,即所有实现都被定义为抽象方法,最终的具体实现全部交给具体类实现。引入该角色主要是为了根据声明不同的抽象类,将类区分为不同的等级结构。
  • 具体类:该角色继承抽象类,主要用于实现抽象类中声明的抽象方法,完成不同等级结构,不同族的业务方法的具体实现。

以形状为类的级别、颜色为族来实例分析实现:

这里写图片描述

等级抽象

进行等级抽象我们需要将不同的形状声明为抽象类(等级划分)并实现公共的抽象接口(Shape),然后具体的实现类继承自对应的抽象类;

//形状公共接口
public interface Shape {
    void draw();
}
//圆形抽象类Circle
public abstract class Circle implements Shape {
    public abstract void draw();
}
//长方形抽象类Rectange
public abstract class Rectange implements Shape {
    public abstract void draw();
}
//其他图形抽象类... ...

具体的实现类继承自对应的抽象类,继承自不同的抽象类就相当于将类划分为不同的等级,如:

//具体颜色的Circle实现
public class BlueCircle extends Circle {
    @Override
    public void draw() {
        System.out.println("绘制蓝色的圆");
    }
}
public class RedCircle extends Circle {
    @Override
    public void draw() {
        System.out.println("绘制红色的圆");
    }
}

//具体颜色的Rectange实现
public class RedRectange extends Rectange{
    @Override
    public void draw() {
        System.out.println("绘制红色长方形");
    }
}
public class BlueRectange extends Rectange {
    @Override
    public void draw() {
        System.out.println("绘制蓝色长方形");
    }
}

具体类族抽象

具体类族的划分我们以颜色为基础,不同类族的对象我们通过对应的具体工厂来创建。所以首先我们需要定义一个抽象工厂,具体工厂(族)实现抽象工厂的方法来生成一组具体对象。

//抽象工厂ShapeFactory 
public interface ShapeFactory {
    Shape getCircle();
    Shape getRectange();
}
//RedShapeFactory(他所代表的是红色形状这一族)
public class RedShapeFactory implements ShapeFactory {
    @Override
    public Shape getCircle() {
        return new RedCircle();
    }

    @Override
    public Shape getRectange() {
        return new RedRectange();
    }
}
//BlueShapeFactory(他所代表的是兰色形状这一族)
public class BlueShapeFactory implements ShapeFactory {
    @Override
    public Shape getCircle() {
        return new BlueCircle();
    }
    @Override
    public Shape getRectange() {
        return new BlueRectange();
    }
}
//...其他族...

等级以及族类划分完成之后,我么的客户端在使用时只需要知道抽象工厂(ShapeFactory )以及具体工厂(如BlueShapeFactory )就可以获得指定族的所有形状。

public class TestDemo {
    public static void main(String[] args) {
        ShapeFactory redShapeFactory = new RedShapeFactory();
        Shape circle = redShapeFactory.getCircle();
        circle.draw();
        Shape rectangle = redShapeFactory.getRectange();
        rectangle.draw();

        ShapeFactory greenShapeFactory = new GreenShapeFactory();
        Shape greenCircle = greenShapeFactory.getCircle();
        greenCircle.draw();
    }
}

根据我们上面对抽象工厂模式的描述,我们大致能够明白,如果我们在上例的基础上想要增加绿色或者其他颜色的图形时,我们只需要增加一个绿色产品工厂(GreenShapeFactory),同时继承不同的图形抽象类实现不同颜色的图形具体类即可,看起来如下:

//GreenShapeFactory
public class GreenShapeFactory implements ShapeFactory {
    @Override
    public Shape getCircle() {
        return new GreenCircle();
    }
    @Override
    public Shape getRectange() {
        return new GreenRectange();
    }
}

//GreenRectange 
public class GreenRectange extends Rectange {
    @Override
    public void draw() {
        System.out.println("绘制绿色长方形");
    }
}
//GreenCircle
public class GreenCircle extends Circle{
    @Override
    public void draw() {
        System.out.println("绘制绿色圆");
    }
}

3、单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。(构造函数是私有的)
  • 单例类必须给所有其他对象提供这一实例。

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的。

3.1、单例模式的优缺

优点:

  • 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  • 避免对资源的多重占用(比如写文件操作)。

缺点:

  • 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

单例模式使用注意事项:

  1. 使用时不能用反射模式创建单例,否则会实例化一个新的对象
  2. 使用懒单例模式时注意线程安全问题
  3. 饿单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式)

单例防止反射漏洞攻击:

private static boolean flag = false;
private Singleton() {
	if (flag == false) {
		flag = !flag;
	} else {
		throw new RuntimeException("单例模式被侵犯!");
	}
}
public static void main(String[] args) {
}

3.2、单例创建方式

  1. 饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
  2. 懒汉式: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
  3. 静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
  4. 枚举单例: 使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞, 缺点没有延迟加载。
  5. 双重检测锁方式 :

3.3、饿汉式

  • 是否多线程安全:是
  • 描述:这种方式比较常用,但容易产生垃圾对象。
  • 优点:没有加锁,执行效率会提高。
  • 缺点:类加载时就初始化,浪费内存。
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

3.4、懒汉式

懒汉式也可以分为线程安全和不安全两种实现方式。

线程不安全:

  • 描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
  • 这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

线程安全:

  • 描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
  • 优点:第一次调用才初始化,避免内存浪费。
  • 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

3.4、静态内部类式

是否多线程安全:

实现难度:一般

描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟饿汉式方式不同的是:饿汉式方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比饿汉式方式就显得很合理。

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}

3.5、枚举单例

是否多线程安全:

实现难度:

描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
不能通过 reflection attack 来调用私有构造方法。

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

3.6、双检锁式

是否多线程安全:

实现难度:较复杂

描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。

双重重检测是为了防止多线程下重复初始化实例,所以要防止指令重排序。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
            if (singleton == null) {  
                singleton = new Singleton();  
            }  
        }  
    }  
    return singleton;  
    }  
}

三、行为型模式

        行为型模式关注对象之间的通信和协作,以实现更灵活、松耦合的设计。这些模式帮助我们定义对象之间的交互方式,以便更好地组织代码并实现系统的功能。

3.1、责任链模式

        责任链模式(Chain of Responsibility): 使多个对象都有机会处理同一请求,从而避免请求的发送者和接受者之间的耦合关系,每个对象都是一个处理节点,将这些对象连成一条链,并沿着这条链传递该请求。

使用场景

  1. 日志记录:在应用程序中,可能需要记录不同级别的日志信息。使用责任链模式可以将日志记录的操作从具体的记录器中分离出来,使得记录日志的操作可以被动态地添加到链中。
  2. 异常处理:当一个对象发生异常时,可能需要将该异常传递给下一个处理者。使用责任链模式可以实现这一点,每个处理者都可以决定是否处理该异常或者将其传递给下一个处理者。
  3. 权限控制:在一些系统中,不同的用户可能具有不同的权限。使用责任链模式可以将权限检查的操作从具体的验证器中分离出来,使得不同的验证器可以决定是否进行权限检查。
  4. 缓存系统:在一些系统中,可能需要对数据进行缓存。使用责任链模式可以将缓存操作从具体的缓存器中分离出来,使得不同的缓存器可以决定是否进行缓存操作。

总之,责任链模式适用于需要将请求发送到一系列处理者中的系统,这些处理者可以根据自己的条件来决定是否处理请求。

3.1.1、实现流程

举例应用说明:

        比如一个请求进来之后,需要对请求传递的对象进行多个不同的处理,那个可以将多个不同的处理划分到多个节点中,某个节点只做部分处理,然后将对象传到下一个节点中,就像一个单链表一样,每个节点拿着后一个节点位置。

        例如参数传递一个两个参数,第一步校验两个值是否在[1,5]范围内,第二步算两个参数相加的值,第三步算两个参数相乘的值,第四步将相乘的值减去相加的值,判断是否大于零。

1、用到了一个实体类,先创建实体类

@Data
public class ParamEntry {
    private Integer param1;
    private Integer param2;
    /**
     * 相乘
     */
    private Integer multiply;
    /**
     * 相加
     */
    private Integer addition;
    /**
     * 相减
     */
    private Integer subtract;
}

2、定义抽象类,作为职责步骤的父类

public abstract class CorStep {

    /** 下一个规则节点 */
    public CorStep nextStep;
    /**
     * 本规则节点的职责,需要做的处理
     * @param paramEntry
     */
    public abstract void handleStep(ParamEntry paramEntry);
}

3、定义职责类,实现抽象类,完成每个职责节点的具体任务。

        第一步节点的实现类

@Component
public class CheckParameterValueStep extends CorStep {
    @Override
    public void handleStep(ParamEntry paramEntry) {
        //判断两个参数值是否在【1,5】中
        Integer param1 = paramEntry.getParam1();
        Integer param2 = paramEntry.getParam2();
        if (param1 < 1 || param1 > 5){
            return;
        }
        if (param2 < 1 || param2 > 5){
            return;
        }
        nextStep.handleStep(paramEntry);
    }
}

        第二步节点的实现抽象类,完成相加

@Component
public class AdditionByParamStep extends CorStep {
    /**
     * 两个参数相加
     * @param paramEntry
     */
    @Override
    public void handleStep(ParamEntry paramEntry) {
        Integer param1 = paramEntry.getParam1();
        Integer param2 = paramEntry.getParam2();
        paramEntry.setAddition(param1+param2);
        nextStep.handleStep(paramEntry);
    }
}

        第三步继承抽象类实现handleStep方法执行相乘

@Component
public class MultiplyByParamStep extends CorStep{
    /**
     * 将两个参数相乘
     * @param paramEntry
     */
    @Override
    public void handleStep(ParamEntry paramEntry) {
        Integer param1 = paramEntry.getParam1();
        Integer param2 = paramEntry.getParam2();
        paramEntry.setMultiply(param1*param2);
        //调用下一个节点的处理任务方法
        nextStep.handleStep(paramEntry);
    }
}

        第四步,在本次测试的责任链中只有四个步骤,所以这也是左后异步,依旧是继承抽象类,实现handleStep方法,在方法的末尾,不再调用下一个节点。

@Component
public class SubtractByMulAndAddStep extends CorStep {
    @Override
    public void handleStep(ParamEntry paramEntry) {
        Integer multiply = paramEntry.getMultiply();
        Integer addition = paramEntry.getAddition();
        paramEntry.setSubtract(multiply-addition);
        System.out.println("最终处理完成:"+paramEntry.toString());
    }
}

4、定义职责类的持有者类,创建方法作为调用的接口,并执行责任链的处理顺序,

/**
 * 责任链模式
 * 1 指定责任链的顺序,每个节点拿着下一个节点的位置,最后一个节点的nextStep为空。
 * 2 调用责任链的开头
 */
@Component
public class CorStepHolder {
    private CorStep firstStep;
    @Resource
    AdditionByParamStep additionByParamStep;
    @Resource
    CheckParameterValueStep checkParameterValueStep;
    @Resource
    MultiplyByParamStep multiplyByParamStep;
    @Resource
    SubtractByMulAndAddStep subtractByMulAndAddStep;

    /**
     * 编排步骤,在类对象创建时
     */
    @PostConstruct
    private void init(){
        //第一步,执行checkParameterValueStep
        firstStep = checkParameterValueStep;
        //第二步,为第一步的下一节点指定第二步
        checkParameterValueStep.nextStep = multiplyByParamStep;
        //第三步,为第二步的下一节点指定第三步
        multiplyByParamStep.nextStep = additionByParamStep;
        //第四步,为第三步指定下一节点的对象
        additionByParamStep.nextStep = subtractByMulAndAddStep;
    }
    /**
     * 执行任务链
     * @param paramEntry
     */
    public void executionStep(ParamEntry paramEntry){
        if (!StringUtils.isEmpty(paramEntry)){
            if (paramEntry.getParam1() != null && paramEntry.getParam2() != null){
                firstStep.handleStep(paramEntry);
            }
        }
    }
}

总结

        责任链模式的实现总共需要三种类,一种是抽象类,作为所有节点类的父类;一种是节点类,继承父类中“具体处理责任”的方法;第三中类时持有责任链的类,在该类中首先定义责任链的顺序,然后调用首节点。

你可能感兴趣的:(程序员必学计算机基础知识,设计模式)