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
抽象只调用实现中的方法,通过调用实现的方法桥接起来。
桥接模式举例
-
消息管理
消息类型(抽象层)即时消息,延时消息
消息分类(实现层)手机短信,邮件消息,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; }
}