第一篇:浅析设计模式1 —— 工厂模式
第二篇:浅析设计模式2 —— 策略模式
第三篇:浅析设计模式3 —— 装饰者模式
概述
模版方法模式的结构相对简单,主要包含两大类:抽象类、具体类,抽象父类中首先定义好算法流程,具体的步骤细节延迟到具体子类中执行。
角色 | 关系 | 作用 |
抽象类 Abstract Class | 具体类的父类 | 定义一个抽象的模版类,给出算法的骨架,包含一个模版方法和若干个基本方法(抽象方法、具体方法、钩子方法) |
具体类 Concrete Class | 抽象构件的接口实现类 | 定义一个具体的实现类,实现抽象类中定义的抽象方法和钩子方法。 |
有了上述的基本概念,我们将装饰者模式的使用步骤概括为:
step1:创建抽象类,定义一个算法骨架,包含一个模版方法和若干个基本方法:
模版方法:算法流程,定义基本方法的执行顺序;
基本方法 - 具体方法:在抽象类中实现,可被具体类继承或重写;
基本方法 - 抽象方法:在抽象类中声明,由具体类实现;
基本方法 - 钩子方法:在抽象类中实现,包含一种用于判断的方法、一种由具体类重写的空方法。
step2:创建具体类,实现抽象类中定义的抽象方法和钩子方法;
使用示例
// 创建抽象父类,定义算法骨架
public abstract class TMAbstractClass {
public final void shopOnline() {
selectItems();
checkoutItems();
if(isReturnItemsHook1()) {
returnItems();
} else if(isExchangeItemsHook2()) {
exchangeItems();
//假设一次性换到满意的商品
confirmTheReceipt();
} else {
confirmTheReceipt();
}
terminateTransaction();
}
protected abstract void selectItems();
protected void checkoutItems() {
System.out.println("下单支付");
}
public boolean isReturnItemsHook1() {
return false;
}
protected void returnItems() {
}
public boolean isExchangeItemsHook2() {
return false;
}
protected void exchangeItems() {
}
protected void confirmTheReceipt() {
System.out.println("确认收货");
}
protected void terminateTransaction() {
System.out.println("终止交易");
}
}
// 定义具体子类1:购买商品1
public class TMConcreteClass1 extends TMAbstractClass{
protected void selectItems() {
System.out.println("选择商品1");
}
public boolean isReturnItemsHook1() {
return true;
}
protected void returnItems() {
System.out.println("退货退款");
}
}
// 定义具体子类2:购买商品2
public class TMConcreteClass2 extends TMAbstractClass{
protected void selectItems() {
System.out.println("选择商品2");
}
public boolean isExchangeItemsHook2() {
return true;
}
protected void exchangeItems() {
System.out.println("换货");
}
}
//客户端调用
public class userPayForItem() {
public static void main(String[] args) {
System.out.println("购物记录1:");
TMAbstractClass shopRecord1 = new TMConcreteClass1();
shopRecord1.shopOnline();
System.out.println();
System.out.println("购物记录2:");
TMConcreteClass2 shopRecord2 = new TMConcreteClass2();
shopRecord2.shopOnline();
}
}
购物记录1:
选择商品1
下单支付
退货退款
终止交易
购物记录2:
选择商品2
下单支付
换货
确认收货
终止交易
JDK源码赏析
模板方法模式在框架源码中使用也很广泛,比如:JDK 源码中 AbstractList 抽象类、Mybatis 源码中 BaseExecutor 抽象类。本文以 AbstractList 为例,分析模版方法模式在源码中如何应用。AbstractList 是 ArrayList 的父类,也就是模版类,它包含的方法有很多,这里主要介绍一下 addAll() 方法。
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
add(index++, e);
modified = true;
}
return modified;
}
}
事实上,AbstractList 中的方法除了一些私有方法不能被子类访问,大多数方法都和 addAll() 一样,可由子类选择是否修改:如果子类需要做个性化的实现就要修改,如果不需要则直接按照父类方法的逻辑执行。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
}
private final AbstractList<E> l;
private final int offset;
abstract public E get(int index);
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
左边是父类AbstractList中的,右边是ArrayList中的方法。在父类中没有直接写出实现代码,而是让子类自己手动去实现。除此之外其实还有一个方法就是AbstractList父类AbstractCollection中的toString方法。在ArrayList中是没有的,但是平常在写代码时候,是可以直接调用的,这就是一个公共的方法。
优缺点及适用场景
团队介绍