编程是一门艺术,大批量的改动显然是非常丑陋的做法,用心的琢磨写的代码让它变的更美观。
在面向对象程序设计过程中,常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。未知的步骤可以延迟到子类中实现。可以将固定的步骤设计一个模板设计在父类,未知的操作设置一个抽象方法,让子类去实现具体的操作。
模板方法(Template Method)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤,它是一种类行为型设计模式。
该模式的主要优点:
它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
它在父类中提取了公共的部分代码,便于代码复用。
部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
该模式存在的不足:
对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。
根据需求整理出算法的执行步骤,将不变的固定的步骤实现在父类,可变的定义成抽象方法,让子类去实现,不过抽象方法的执行步骤需要在父类定义好。
场景介绍:购买商品,到收银台结算,整个流程经历:汇总商品费用,处理优惠活动,进行支付,但是支付可以有多个方式:现金、网络与代付,但是支付方式是用户选择的,其他的流程是一样的,所以可以使用模板设计模式,将不变的流程设计成固定的模式,将未知的步骤设计成抽象方法,让子类实现类去实现就可以。
/**
* 模板方法模式:真个算法过程是固定的,但是有一些步骤是未知的,需要延迟到子类去实现,需要延迟到子类的需要定义为抽象方法,这就是模板设计模式的
* 购物车费用结算过程
*
* 结算的方式是用户的行为 这个只有当用户真正结算的时候才只能得知,所以需要延迟到子类去实现
*/
public abstract class ShoppingCart {
/**
* 折扣
*/
private Discount discount;
/**
* 购买水果集合
*/
private List<Fruit> products = new ArrayList<>();
public ShoppingCart(List<Fruit> products){
this.products = products;
}
/**
* 注入不同的优惠方案
* @param discount
*/
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);
}
/**
* 计算金额
* @return
*/
private int balance(){
int money = 0;
System.out.print("商品清单:");
for (Fruit fruit : products){
fruit.draw();
System.out.print(",");
money += fruit.price();
}
return money;
}
/**
* 支付方式 是用户行为,是用户真正支付的时候才知道的
* 所以需要延迟到子类去实现
* @param money
*/
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 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 CartShopping(products);
/*注入优惠方案*/
cart.setDiscount(new FullDiscount());
cart.submitOrder();
}
模板方法模式通常适用于以下场景: