文章目录
模板模式(Template Pattern)
应用
使用模板(Java)
public class TemplateMethodPattern {
public static void main(String[] args) {
AbstractTemplate a = new ConcreteTemplateA();
a.templateOperation();
System.out.println("-------------------------------------");
AbstractClass b = new ConcreteTemplateB();
b.templateOperation();
}
}
//抽象类
abstract class AbstractTemplate {
// 统一的操作,不可变
public final void templateOperation() {
//TODO 统一的操作
System.out.print("1.hookOperation()——");
hookOperation();
System.out.println();
System.out.print("2.abstractMethod()——");
abstractMethod();
System.out.println();
System.out.print("3.calculateAmount()——");
calculateAmount();
System.out.println();
}
//抽象方法(子类必须实现)
protected abstract void abstractMethod();
// 钩子方法(空实现或者默认值)
protected void hookOperation() { }
//具体方法,子类无法知晓
private void calculateAmount() { System.out.print("抽象类中具体方法的实现内容"); }
}
//具体的子类
class ConcreteTemplateA extends AbstractTemplate {
//重写抽象方法
@Override
protected void abstractMethod() { System.out.print("具体操作,子类A_执行"); }
}
class ConcreteTemplateB extends AbstractTemplate {
//重写抽象方法
@Override
protected void abstractMethod() {
// 具体模板2 业务逻辑
System.out.print("具体操作,子类B_执行");
}
//重写钩子方法
@Override
protected void hookOperation() {
System.out.print("重写了钩子方法,子类B_执行");
}
}
应用实例
- 类
Map
- 类
HashMap
简介
准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
——《JAVA与模式》
介绍
模板模式(Template Pattern),又叫模板方法模式(Template Method Pattern)行为型模式。
在模板模式中,基本算法固定,算法中部分代码抽象到方法并公开到子类。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
意图:
- 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
- 模板方法使得子类通过改变一个算法中的指定的一部分代码,从而获得到符合条件的算法。
UML图
角色
抽象类(AbstractTemplate):在抽象类中定义了一系列基本操作,这些基本操作有些是具体的,有些也可以是抽象的。其中有一个具体的方法作为模板方法,该方法定义了一个算法的框架,该方法中根据具体情况进行其中抽象方法进行调用。而该抽象方法将延迟到具体子类中进行实现。
- 模板抽象类方法类型
- 模板方法:定义统一模板算法的方法,子类一般不需要重写。一般加上final防止子类篡改。
- 抽象方法:在抽象类声明、调用,但由其具体子类实现。
- 具体方法:在抽象类中声明并实现,根据情况来确定是否为子类可知。
- 钩子方法:在抽象类中声明并实现(可以是空的实现),子类视情况进行重写覆盖,一般是逻辑判断方法。钩子方法的名字应当以do开始,例如doGet()。
**具体子类(ConcreteTemplate):**它是抽象类的子类,用于实现在父类中声明的抽象方法以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
主要解决:
- 大部分算法通用,却因为部分细节不一致,而需要每次都重写该方法。而导致了大量代码重复问题。
何时使用:
- 有一些通用的方法
如何解决:
- 将通用算法抽象出来。
关键代码:
- 通用代码在抽象类实现,变动的细节逻辑在子类实现。
优点:
- 封装不变部分,扩展可变部分。
- 提取公共代码,便于维护。
- 行为由父类控制,子类实现。
缺点:
- 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景:
- 有多个子类共有的方法,且逻辑相同。
- 重要的、复杂的方法,可以考虑作为模板方法。
注意事项:
为防止恶意操作,一般模板方法都加上 final 关键词。
JDK使用分析
类Map中的使用
public interface Map<K,V> {
...
V remove(Object key);
...
default boolean remove(Object key, Object value) {
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key);
return true;
}
}
在上述代码接口中:
Map.remove(Object key)
等作为抽象方法,在子类中进行实现。Map.remove(Object key, Object value)
作为模板方法,是调用抽象方法的固定算法。
public abstract class AbstractMap<K,V> implements Map<K,V> {
public V remove(Object key) {
Iterator<Entry<K,V>> i = entrySet().iterator();
Entry<K,V> correctEntry = null;
if (key==null) {
while (correctEntry==null && i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
correctEntry = e;
}
} else {
while (correctEntry==null && i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
correctEntry = e;
}
}
V oldValue = null;
if (correctEntry !=null) {
oldValue = correctEntry.getValue();
i.remove();
}
return oldValue;
}
}
而在Hashmap
的父类AbstractMap
便实现了上述的抽象方法,从而组合为符合该类需要的remove算法。
oldValue = correctEntry.getValue();
i.remove();
}
return oldValue;
}
}
而在`Hashmap`的父类`AbstractMap`便实现了上述的抽象方法,从而组合为符合该类需要的remove算法。