算法的流程、骨架在抽象类中已经固定,而将一些步骤延迟到子类中。使得子类可以不改变算法的结构即可重定义其中的某些特定步骤
一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
事例
需求:客户买水果的流程“提交订单->结算->支付”,而支付有三种方式“线上、会员卡、现金”
业务结构如图:
抽象类及其实现类如下:
public abstract class Shopping {
// 模板方法是定义业务流程的,加final防止被修改
public final void buy() {
submit();
balance();
pay();
}
private void submit() {
// 提交订单
}
private void balance() {
// 结算
}
// 具体实现由子类完成
protected abstract void pay();
}
不同的细节交给不同的子类去实现
public class OnlineShopping extends Shopping {
@Override
protected void pay() {
// 线上支付
}
}
public class CardShopping extends Shopping {
@Override
protected void pay() {
// 会员卡支付
}
}
public class CashShopping extends Shopping {
@Override
protected void pay() {
// 现金支付
}
}
测试,客户下单。选择合适的子类去实现抽象类,并调用它的模板方法
private void shop(){
// 现金支付。用子类CashShopping
Shopping shopping = new CashShopping();
// 调用抽象类的模板方法
shopping.buy();
}
总结
适用场景
- 有多个子类共有的方法,且逻辑流程相同
- 重要的、复杂的方法,可以考虑作为模板方法
优点
- 封装不变的,扩展可变的
- 提取了公共代码便于维护
- 行为由父类控制,子类实现
缺点
- 业务增多时,子类也增多