Java 设计模式(剖析spring源码 jdk源码 等)

Java 设计模式

高内聚,低耦合,可维护,可读性

设计模式七大设计原则

单一职责原则

Single Responsibility

一个类应该只负责一项单一的职责

  • 降低类的复杂度,一个类负责一个单一职责
  • 提高类的可可读性和可维护性
  • 降低变更带来的风险

接口隔离原则

Interface Segregation Priciple

一个类对另一个类的依赖应该建立在最小的接口上。客户端不应该依赖它不需要的接口。

如果一个接口的一部分被A依赖,另一部分被B依赖,这个时候应该把接口拆分成两个字接口,实现接口隔离原则,减少冗余代码。

依赖倒转原则

Dependence Inversion Priciple

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 依赖倒转的中心思想是面向接口编程
  • 相对于细节的多变性,抽象的东西要稳定,细节就是具体实现

依赖关系传递的三种方式:

  • 接口传递
  • 构造方法传递
  • setter方法传递

依赖倒转原则的注意事项和细节:

  • 低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好
  • 变量的声明类型尽量都是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化 (父类方便拓展子类)
  • 继承时遵循里氏替换原则

里氏替换原则

如果对每个类型为T1对对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2室类型T1点字类型。换句话说:所有引用基类的地方必须能透明地使用其子类的对象。

使用继承的时候,子类尽量不要重写父类的方法。

里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖来解决问题。

  • 聚合:整体和部分的关系,可以分开。成员类可以脱离整体对象存在。汽车这个类包含引擎类

  • 组合:整体和部分的关系,不可以分开。一旦整体不存在,成员类也不可以存在。例如某公司的某个部门,公司倒闭了,部门也不存在了。

  • 依赖:A类的对象作为B类的一个成员变量

开闭原则 ocp

Open Close Principle:是编程中最基础,最重要的设计原则。

  • 一个软件实体,例如类,模块,函数都应该对扩展(提供方)开放,对修改(使用方)关闭。用抽象构建框架,用实现扩展细节。
  • 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有代码。
  • 设计模式的目的就是遵循开闭原则。

迪米特法则

Demeter Principle:最小知道原则,一个类对自己依赖的类知道的越少越好。除了对外暴露public方法,不对外泄露任何信息。只和直接朋友进行通讯。

合成复用原则

尽量使用聚合,合成, 而不是使用继承

UML基本介绍

  • Dependency: 依赖(使用)。只要一个类在类中用到了对方,方法返回值,方法参数,函数中的局部变量。

  • Association: 关联(一对多; 一对一; 双向一对一)。一个人和一个身份证是一一对应的。如果人这个类中有身份证类,身份证类中也有人这个类,那么他们关系是双向的。

  • Generalization: 泛化(继承)

  • Realization: 实现

  • Aggregation: 聚合 (通过set方法传入别的类,称为聚合)。如果A类中可以有多个B类,就是多聚合,否则就是单聚合(一台电脑可以有多个内存)。聚合类可以分开,例如鼠标可以离开电脑存在。

  • Composite: 组合(当B类被实例化的时候,A类也被实例化的时候,称为组合)。如果类创建的时候自动创建了别的类,则是组合关系。例如:

    public class A {
      private B b = new B();
    }
    
    public class B {
    }
    

    这种情况下,A创建的时候,B直接被创建,所以是共生死的,所以是组合关系。如果删除的时候进行极联删除,那么就是组合关系。

设计模式概略

  • 创建型模式:单例模式,抽象工厂模式,原型模式,创建者模式,工厂模式
  • 结构型模式:适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式
  • 行为型模式:模板方法模式,命令模式,访问者模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式(Interpreter模式),状态模式,策略模式,职责链模式(责任链模式)

单例模式

保证整个软件中,某个类只能存在一个对象实例。并且该类只提供一个取得其对象实例的方法(静态方法),比如 ConnectionFactory,SessionFactory。

饿汉式(静态常量)

class type1 {
    //饿函式 静态成员变量
    private static type1 instance = new type1();

    private type1() {};

    public static type1 getInstance() {
        return instance;
    }
}

饿汉式(静态代码块)

class type2 {
    //饿汉式 静态代码块
    private static type2 instance;

    static {
        instance = new type2();
    }

    private type2() {};

    public static type2 getInstance() {
        return instance;
    }
}

懒汉式(线程不安全)

class type3 {
    //懒汉式
    private static type3 instance;
    
    private type3() {};
    
    public static type3 getInstance() {
        if (instance == null)
            instance = new type3();
        return instance;
    }
}

懒汉式(线程不安全,同步方法)

class type4 {
    //懒汉式
    private static type4 instance;

    private type4() {};

    public static type4 getInstance() {
        if (instance == null)
            synchronized (type4.class) {
                instance = new type4();
            }
        return instance;
    }
}

多个线程进入if语句后,好几个线程都会创建instance,线程不安全,不能使用!

懒汉式(线程安全,同步代码块,双重检查)

class type5 {
    //懒汉式 线程安全 double check
    private static volatile type5 instance;
    
    private type5() {}
    
    public static type5 getInstance() {
        if (instance == null) 
            synchronized (type5.class) {
                if (instance == null)
                    instance = new type5();
            }
        return instance;
    }
}

静态内部类(线程安全)

写一个静态内部类,该类中有一个静态属性 Singleton

属于懒汉式,外部类的加载不会导致静态内部类的加载

class type6 {
    //静态内部类
    private type6() {}
    
    private static class SingletonInstance {
        private static final type6 INSTANCE = new type6();
    }
    
    public static type6 getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

枚举

可以防止反序列化重新创建新的对象

class type7 {
    //枚举
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);
    }
}

enum Singleton {
    INSTANCE;
    public void sayOK() {
        System.out.println("ok ");
    }
}

单例模式总结

工具类,数据源,重量级对象等都可以使用单例模式

工厂模式

简单工厂模式

属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。

简单工厂模式也叫做静态工厂模式

public static Object createObject() {}

工厂方法模式

定一个抽象类class来表示factory,具体的实例化对象操作下放到子类(继承这个抽象类的类)实现。

抽象工厂模式

把抽象的类换成interface,最顶层是抽象接口,多个子类工厂族来实现不同的对象实例化。

interface AbstractFactory { createObject() }
class SubFactory1 implements subFactory1 { createObject() }
class SubFactory2 implements subFactory2 { createObject() }

/**
*	使用的时候只需要传入一个具体的实现子类,然后通过其来实例化对象,而使用层面只需要用interface来表明需要使用的类,可以减少代码修改量
**/
public static void main(String[] args) {
  //如果想用子工厂1来创建对象
  createBean(new SubFactory1);
  
  //如果想用子工厂2来创建对象
  createBean(new SubFactory2);
}
// 这样写的好处是,createBean的函数主体不需要更具工厂族的变化而变化
public static Object createBean(AbstractFactory a) {
  return a.createObject();
}

原型模式

原型模式需要自己配置一个clone类

浅拷贝

prototype:类需要implements Cloneable,即使他是个空接口(不然会有class不支持克隆报错),并且重写Object类的clone方法,即使这个方法是浅拷贝。对于基本数据类型,浅拷贝会直接进行值传递,对于引用数据类型的成员变量,浅拷贝只会复制目标地址,也就是说String类型的对象只能复制内存地址。

深拷贝

  • 通过重写clone方法来实现深拷贝

    相当于多次套嵌clone方法来实现深拷贝

  • 通过对象序列化来实现深拷贝(推荐使用)

    ByteArrayOutputStream bos = null;
    ObjectOutputStream oos = null;
    ByteArrayInputStream bis = null;
    ObjectInputStream ois = null;
    
    //序列化
    bos = new ByteArrayOutputStream();
    oos = new ObjectOutputStream(bis);
    oos.writeObject(this);
    
    //反序列化
    bis = new ByteArrayInputStream(bos.toByteArray());
    ois = new ObjectInputStream(bis);
    Object obj = ois.readObject();
    

    通过序列化和反序列化引用类型都被深拷贝了,String类型也会是两个不同的值。

建造者模式

把产品和产品建造过程解耦 --> 建造者模式,通过一步一步建造一个复杂的对象

建造者模式四个角色

  • Product: 产品角色
  • Builder: 创建Product各个部件指定的接口/抽象类
  • ConcreteBuilder: 实现接口,构建和装配各个部件
  • Director: 聚合了一个Builder,构建使用Builder接口的对象,创建一个复杂的对象,两个作用:1.隔离客户与对象的生产过程 2.负责控制产品对象的生产过程。

四个角色对应的例子

public class House {
  private String base;
  private String wall;
  private String roofed;
  // getters and setters
}
//只说明房子建造需要的函数,建造流程交给Director处理
public abstract class HouseBuilder {
  protected House house - new House();
  
  public abstract void buildBase();
  public abstract void buildWalls();
  public abstract void buildRoof();
  // 返回建造好后的房子
  public House buildHouse() {
    return house;
  }
}
public class ConcreteHouseBuilder extends HouseBuilder {
  @Override
  public void buildBase() { System.out.println("Build Base..") }
  // implements another 2 Overrride methods
}
public class HouseBuildDirector {
  HouseBuilder houseBuilder = new HouseBuilder();
  
  public HouseBuildDirector(HouseBuilder hb) {
    this.houseBuilder = hb;
  }
  
  public House constructHouse() {
    houseBuilder.buildBase();
    houseBuilder.buildWall();
    houseBuilder.buildRoof();
    return houseBuilder.buildHouse();
  }
}
// Comsummer / how to build a house?
public class Main {
  public static void main(String[] args) {
    //把具体的HouseBuilder子类传入Director中来实现:
    //在不修改代码的基础上 新增不同的HouseBuilder。因为HouseBuilderDirector中接受的是抽象父类
    HouseBuildDirector hbd = new HouseBuildDirector(new ConcreteHouseBuilder());
    House house = hbd.constructHouse();
  }
}

StringBuilder 源码解析

  • Appendable 接口定义了多个append方法,为抽象建造者,定义了抽象方法
  • AbstractStringBuilder 实现了 Appendable,已经是一个建造者,只是不能实例化
  • StringBuilder 既充当了具体的Director角色,也充当了具体的建造者。建造方法的实现是由父类(AbstractStringBuilder)实现

抽象工厂模式 VS 建造者模式

  • 抽象工厂模式:实现对产品家族的创建,只需要关心产品由什么工厂生产即可
  • 建造者模式:按照一定的蓝图来建造产品,主要是通过装配零件来组装一个产品

适配器模式

基本介绍

适配器模式属于结构型模式,分为三类:

  • 类适配器模式:继承被适配的类,实现接口
  • 对象适配器模式:实现接口,把被适配组合到自身中
  • 接口适配器模式:缺省适配器模式,先设计一个抽象类,提供默认方法(空方法),子类可以有选择覆盖方法。由于是抽象类无法被具体实例化,所以必须重写里面需要的方法来实现实例化。方便子类只使用部分方法,无需关心别的方法。

主要把不兼容的接口融合在一起正常工作。

SpringMVC中的适配器

SpringMVC中的DispatchServlet使用了适配器模式,来适配Controller类。当需要新增Controller类的时候,可以在不修改原有框架代码的基础上,添加HandlerAdapter类即可正常工作。

  • Controller:
public interface Controller {
}

class AnnotationController implements Controller {
    public void doAnnotationController() { System.out.println("annotation..."); }
}

class HttpController implements Controller {
    public void doHttpHandler () { System.out.println("http..."); }
}

class SimpleController implements Controller {
    public void doSimplerHandler() { System.out.println("simple..."); }
}
  • Adapter:
public interface HandlerAdapter {
    void handle(Object controller);
    boolean supports(Object controller);
}

class AnnotationHandlerAdapter implements HandlerAdapter {
    public void handle(Object handler) { ((AnnotationController) handler).doAnnotationController(); }
    public boolean supports(Object handler) { return (handler instanceof AnnotationController); }
}

class HttpHandlerAdapter implements HandlerAdapter {
    public void handle(Object handler) { ((HttpController) handler).doHttpHandler(); }
    public boolean supports(Object handler) { return (handler instanceof HttpController); }
}

class SimpleHandlerAdapter implements HandlerAdapter {
    public void handle(Object handler) { ((SimpleController) handler).doSimplerHandler(); }
    public boolean supports(Object handler) { return (handler instanceof SimpleController); }
}
  • DispatchServlet:
public class DispatchServlet {

    public static List<HandlerAdapter> handlerAdapters = new ArrayList<>();
    public DispatchServlet() {
        handlerAdapters.add(new AnnotationHandlerAdapter());
        handlerAdapters.add(new HttpHandlerAdapter());
        handlerAdapters.add(new SimpleHandlerAdapter());
    }

    public void doDispatch() {
        AnnotationController controller = new AnnotationController();
        HandlerAdapter adapter = getHandler(controller);
        adapter.handle(controller);
    }

    private HandlerAdapter getHandler(Controller controller) {
        for (HandlerAdapter ha : handlerAdapters) 
            if (ha.supports(controller))
                return ha;
        return null;
    }

    public static void main(String[] args) {
        new DispatchServlet().doDispatch();
    }
}

桥接模式

基本介绍

Bridge:将实现和抽象放在两个不同的类层次中,使两个层次可以独立改变。是一种结构型设计模式。Bridge模式基于类的最小设计原则,通过封装,聚合以及继承等行为让不同类承担不同的职责,它的主要特点把抽象和实现独立出来。

例如:折叠式和直立式的不同品牌手机(两种维度,有很多中组合)。使用桥接模式可以使得手机样式和品牌隔离出来。手机类型设计成abstract class,品牌设计成interface,通过new Phone(new Brand()),在手机类型的构造方法中传入品牌接口,能够有效解耦,满足最小设计原则。

桥接模式UML分析

桥接模式四种角色:

  • Abstraction
  • RefinedAbstraction
  • Implementor
  • ConcreteImplementor

抽象只调用实现中的方法,通过调用实现的方法桥接起来。

https://www.runoob.com/wp-content/uploads/2018/06/1528771072-8457-5780d2384acdbb60ec07fc3c71a1.png

桥接模式举例

  • 消息管理

    消息类型(抽象层)即时消息,延时消息

    消息分类(实现层)手机短信,邮件消息,qq消息

  • 银行转帐

    转账分类(抽象层)网上转账,柜台转账

    用户类型(实现层)普通用户,金卡用户

例子代码

假设:有很多种形状,很多种颜色这两个维度。假设颜色是具体实现,形状是抽象类

public interface Color {
  public void bepaint(String shape);
}
public class Gray implements Color {
    @Override
    public void bepaint(String shape) {
        System.out.println("gray " + shape);
    }
}

public abstract class Shape {
  Color color;
  
  public Shape(Color color) {
    this.color = color;
  }
  public abstract void draw();
}
public class Circle extends Shape {

    public Circle(Color color) {
        super(color);
    }
	
    @Override
    public void draw() {
      //抽象调用实现的方法,而不是自己实现,做到抽象和实现分离
        color.bepaint("circle");
    }
}

//主函数调用,先实例化抽象层,再传入实现层
public static void main(String[] args) {
        new Circle(new Gray()).draw();
    }

装饰器模式

概念

动态的将新功能附加到对象上,比继承更有弹性,装饰器模式也体现了开闭原则(ocp)

  • Component充当抽象角色,不应该具体实现。修饰类引用和继承Component类,具体扩展类重写父类方法
  • Decrator是一个装饰类,内含一个被装饰的对象(Component)

一个Component可以被多个Decorator包裹,把整个新Component(component + decorator)当作一个Component重新被Decorator包裹。举例如下:一杯咖啡,不添加任何东西,这个时候加入牛奶后,继续把牛奶咖啡当作一杯咖啡,重新往里面添加巧克力等,以此类推。

PS: 因为要自己套嵌自己,所以Decorator必须同时继承Decorator和内部组合一个Decorator对象;即自己是一个Component对象,并且内部有一个Component对象,才能循环套嵌。

java代码框架如下

public abstract class Component {}

public class ConcreteComponent extends Component {}

public class Decorator extends Component{
  Component component;
  public Decorator(Component com) { this.component = com; }
}

public static void main(String[] args) {
  Component com = new ConcreteComponent();
  com = new Decorator(com);
  //...
  com = new Decorator(com);
}

组合模式

结构型模式,组合模式等本质就是 定一个抽象的接口或类(顶层),每个子实现中都有一个抽象顶层的list。类似于TreeNode,每个节点都有一个指针指向它的子节点。

java 代码框架

public interface component {
  
}

public class A implements component {
  List<component> ls = new ArrayList<>();
}

public class B implements component {
  List<component> ls = new ArrayList<>();
}

这样A中就能套嵌B或者A本身了

外观模式

facade:又称为过程模式,结构型模式,为复杂的多个子系统抽象出一层专门的门面,可以方便操作所有方法(集成所有子系统的方法);而不需要先实例化A系统,调用A系统的方法,实例化B并调用方法。

享元模式

某些创建很费时间空间的大对象,又或是经常使用到的对象,可以使用享元模式,例如Connection等。传统的连接池,就是这个思路。

代理模式

静态代理

基本概念

静态代理在使用的时候,需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口或者是继承相同的父类.静态代理的关键是,代理类内部有个接口或父类的成员变量(用来装被代理对象)。然后代理类重写接口或父类的方法中,调用被代理对象的重写方法,达到目的。

java代码框架
public interface MyInterface {
    public void test();
}
public class A implements MyInterface {
    @Override
    public void test() {
        System.out.println("A 执行方法 test...");
    }
}
public class AProxy implements MyInterface {
    MyInterface myInterface;
    AProxy() {
        if (this.myInterface == null) 
            myInterface = new A();
    }

    @Override
    public void test() {
        System.out.println("静态代理前...");
        this.myInterface.test();
        System.out.println("静态代理后...");
    }
}
//通过主函数调用
public static void main(String[] args) {
        AProxy proxy = new AProxy();
        proxy.test();
    }

动态代理

基本概念

代理对象不需要实现接口,但是目标对象要实现接口,否则不能使用动态代理;代理对象的生成是利用JDK的API,动态的在内存中构建代理对象;动态代理也叫JDK代理,接口代理。代理类所在的包:java.lang.reflect.Proxy;JDK实现代理只要使用newProxyInstance()方法,但是该方法需要接受三个参数,完整写法:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
java 代码框架

MyInterface 和 A 类不变,新增ProxyFactory如下:

package com.xxx.springboot.designPattern.Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactory {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {

        /**
         * ClassLoader: 指定当前目标对象使用的类加载器
         * Class<?> :使用泛型方法确认类型
         * InvocationHandler: 处理事情,执行目标对象的方法时,会触发事情处理器方法,
         * 会把当前执行的目标方法作为参数传入
         *
         * 标准写法:
         * static Object newProxyInstance(ClassLoader loader,
         *      Class<?>[] interfaces, InvocationHandler h)
         *
         * 下面是lambda表达式,原本写法如下:
         *        new InvocationHandler() {
         *             @Override
         *             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         *                 return null;
         *             }
         *         }
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), (Object proxy, Method method, Object[] args) -> {
                    System.out.println("jdk 代理开始");
                    //反射机制调用目标对象的方法
                    Object returnVal = method.invoke(target, args);
                    return returnVal;
                });
    }
}

主函数调用类:

public class Main {
    public static void main(String[] args) {
        MyInterface target = new A();
        MyInterface proxyObject = (MyInterface) new ProxyFactory(target).getProxyInstance();
        System.out.println(proxyObject);
    }
}

返回出来的代理对象是 com.sun.proxy 类型,是内存中动态代理对象

Cglib 代理

基本概念

有时候目标对象只是一个单独的对象,没有实现任何借口,这个时候可以使用目标对象子类来实现代理-Cglib。

Cglib代理也叫做子类代理,在内存中构建一个子类对象从而实现对目标对象功能扩展,也可以属于动态代理。Cglib包低层通过使用字节码处理框架ASM来转换字节码并生成新的类。

代理的类不能是final类型,否则会报错,并且如果对象的方法是final/static,是不会被拦截的,不会执行目标对象额外的业务方法

java 代码框架

A 类

public class A {
    public void run() {
        System.out.println("A  run ....");
    }
}
public class ProxyFactory implements MethodInterceptor {

    Object target;
    public ProxyFactory(Object t) {
        this.target = t;
    }
    //返回一个代理对象
    public Object getProxyInstance() {
        //1.utils 创建一个工具子类 enhancer
        Enhancer enhancer = new Enhancer();
        //2.super 设置父类
        enhancer.setSuperclass(target.getClass());
        //3.callback 设置回调
        enhancer.setCallback(this);
        //4.subClass 创建子类(代理类)
        return enhancer.create();
    }

    // 重写 intercept方法,会调用目标对象方法
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib proxy starting...");
        Object returnVal = method.invoke(target, args);
        System.out.println("cglib proxy submit");
        return returnVal;
    }
}

客户端调用

public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new A());
        A proxyObj = (A) proxyFactory.getProxyInstance();
        proxyObj.run();
    }

模版模式

基本概念

Template Pattern:在一个抽象类公开定义执行它的方法等模板,它的子类可以按需要重写方法,但调用将以抽象类中定义的方法进行。

属于行为型模式

定义操作骨架,具体函数延迟到子类中进行。

public interface buildHouse {
	public template() {
    buildBase();
    buildWall();
    buildRoof();
  }
  
  public void buildBase();
  public void buildWall();
  public void buildRoof();
}

模版模式的钩子方法

在模板方法模式的父类中,定义一个空方法,不做任何事情,子类可以视情况要不要覆盖它,称为钩子。

SpringIOC

SpringIOC容器用到了模版方法。

ConfigurableApplicationContext 中有个空方法 refresh(),其中子类的AbstractApplicationContext中的refresh() 方法就是模板方法。onRefresh() 就是个钩子方法。

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
              //
                this.postProcessBeanFactory(beanFactory);
              //
                this.invokeBeanFactoryPostProcessors(beanFactory);
              //
                this.registerBeanPostProcessors(beanFactory);
              //
                this.initMessageSource();
              //
                this.initApplicationEventMulticaster();
              //钩子方法,为空,由子类自己实现
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

命令模式

基本原理

命令模式:属于行为型模式,请求以命令的形式包裹在对象中,并传给调用对象。在某些场合,比如事物撤销,重做的时候,需要解耦。调用者->命令->接受者。把请求发起者和请求执行者隔离开来,解耦。命令模式容易实现对命令的撤销,类似redo

三个对象:

  • Receiver:真正的命令执行对象
  • Command:命令
  • Invoker:使用命令对象的入口

优点:降低耦合,新的命令方便加入系统

缺点:导致过多的命令类

java代码框架

Receiver: 真正的命令操作者

public class Stock {
    
    private String name = "abc";
    private int quantity = 10;

    public void buy() {
        System.out.println("buy: " + name + " " + quantity);
    }

    public void sell() {
        System.out.println("sell: " + name + " " + quantity);
    }
}

Command: 命令接口以及实现

public interface Order { void execute(); }
public class SellStockCom implements Order {
    private Stock stock;
    public SellStockCom(Stock stock) { this.stock = stock; }
    @Override
    public void execute() { stock.sell(); }
}

public class BuyStockCom implements Order {
    private Stock stock;
    public BuyStockCom(Stock stock) { this.stock = stock; }
    @Override
    public void execute() { stock.buy(); }
}

Invoker: 传入命令并且执行

public class Invoker {
    private List<Order> orderList = new ArrayList<>();
    public void addOrder(Order order) { orderList.add(order); }
    public void executeOrder() {
        for (Order order : orderList)
            order.execute();
        orderList.clear();
    }
}

JDBC Template

这个 execute() 函数,就像上面的Command中对应的 void execute();

@Override
	public <T> T execute(StatementCallback<T> action) throws DataAccessException {
    //......省略
    T result = action.doInStatement(stmtToUse);
    //......省略
  }

上述的 doInStatement() 方法像是 上述例子stock的抽象类

T doInStatement(Statement stmt) throws SQLException, DataAccessException;

内部类 QueryStatementCallback 对应Invoker,消息接收者。里面的doInStatement() 对应 Stock的buy 和 sell方法

class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
            QueryStatementCallback() {}

            public T doInStatement(Statement stmt) throws SQLException {
                ResultSet rs = null;

                Object var4;
                try {
                    rs = stmt.executeQuery(sql);
                    ResultSet rsToUse = rs;
                    if (JdbcTemplate.this.nativeJdbcExtractor != null) {
                        rsToUse = JdbcTemplate.this.nativeJdbcExtractor.getNativeResultSet(rs);
                    }

                    var4 = rse.extractData(rsToUse);
                } finally {
                    JdbcUtils.closeResultSet(rs);
                }
                return var4;
            }

            public String getSql() { return sql; }
        }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值