模板方法实际就是封装固定的流程,像模板一样,第一步做什么,第二步又做什么,都在抽象类中定义好。子类可以有不同的算法实现,在算法框架不被修改的前提下实现某些步骤的算法替换。
在我们的水果店中,清点商品、计算价目、用户支付、送货上门这四个步骤是固定下来的。但是其中用户支付的方式有多种多样,这个是不确定的,而且后续是否会添加新的支付方式也不得而知,因此,用户支付这个步骤可以做成一个接口,延迟到子类中再去实现,这样就有了更好的扩展性。
ShoppingCart是我们的模板方法模式的抽象类,里面定义好了一系列的固定步骤,只有pay()方法是接口没有实现。
/**
* 模板方法模式
* 购物车费用结算过程
*/
public abstract class ShoppingCart {
private Discount discount;
private List<Fruit> products = new ArrayList<>();
public ShoppingCart(List<Fruit> products){
this.products = products;
}
public void setDiscount(Discount discount) {
this.discount = discount;
}
//提交订单主流程
public void submitOrder(){
//计算商品金额
int money = balance();
System.out.println("商品总金额为:"+money+"元");
//优惠减免
money = discount.calculate(money);
System.out.println("优惠减免后:"+ money+"元,");
//保存订单
pay(money);
//送货上门
sendHome();
}
//计算金额
private int balance(){
int money = 0;
System.out.print("商品清单:");
for (Fruit fruit : products){
fruit.draw();
System.out.print(",");
money += fruit.price();
}
return money;
}
private void sendHome(){
System.out.println("三公里以内,免费送货上门");
}
//提交保存
protected abstract void pay(int money);
}
下面是四种不同的支付方式:
/**
* 模板方法模式
* 购物车费用结算过程
*/
public class CartShopping extends ShoppingCart{
public CartShopping(List<Fruit> products) {
super(products);
}
@Override
protected void pay(int money) {
System.out.println("会员卡结算,立减10,金额:"+ (money - 10)+",增加积分:"+10*money);
}
}
/**
* 模板方法模式
* 购物车费用结算过程
*/
public class CashShopping extends ShoppingCart{
public CashShopping(List<Fruit> products) {
super(products);
}
@Override
protected void pay(int money) {
System.out.println("现金结算,假一罚十");
}
}
/**
* 模板方法模式
* 购物车费用结算过程
*/
public class OnlineShopping extends ShoppingCart{
private OrderService orderService = new OrderServiceImpl();
public OnlineShopping(List<Fruit> products) {
super(products);
}
@Override
protected void pay(int money) {
System.out.println("微信/支付宝结算,减免5元,请支付:"+(money - 5)+"元");
int orderId = orderService.saveOrder();
}
}
/**
* 模板方法模式
* 其他人代付费用结算过程
*/
public class OtherPayShopping extends ShoppingCart{
public OtherPayShopping(List<Fruit> products) {
super(products);
}
@Override
protected void pay(int money) {
System.out.println("代付成功");
}
}
最终在使用时:
/**
* 模板方法模式
* 订单费用结算过程
*/
public class ShoppingCartClient {
private static Map<String, Discount> disCounts = new HashMap();
static {
disCounts.put("full",new FullDiscount());
disCounts.put("newer",new NewerDiscount());
disCounts.put("second",new SecondDiscount());
}
public static void main(String[] args) {
List<Fruit> products = new ArrayList();
products.add(StaticFactory.getFruitApple());
products.add(StaticFactory.getFruitBanana());
products.add(StaticFactory.getFruitOrange());
ShoppingCart cart = new OnlineShopping(products);
//注入优惠方案
// String discount = "second";
// cart.setDiscount(disCounts.get(discount));
cart.submitOrder();
}
}
在软件开发中遇到类似的情况:某个方法的实现需要多个步骤,其中有些步骤是固定的;而有些步骤并不固定,存在可变性。为了提高代码的复用性和系统的灵活性,可以使用模板方法模式来应对这类情况。
定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类不改变一个算法的结构即可重定义算法的某些特定步骤。