模板方法模式(行为型)

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

一、模板方法介绍

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

主要解决:一些方法通用,却在每一个子类都重新写了这一方法。

何时使用:有一些通用的方法。

如何解决:将这些通用算法抽象出来。

关键代码:在抽象类实现,其他步骤在子类实现。

1、业务场景:水果店不断扩展结算方式,希望不影响购物流程

java 如何画方案图 java方案设计_java 如何画方案图

2、模板方法模式 ---------在父类中编排主流程,将步骤实现延迟到子类去实现。将支付方式,延迟到子类去完成

java 如何画方案图 java方案设计_设计模式_02

3、时序图:

java 如何画方案图 java方案设计_System_03

核心解释:

1)先将主流程框架逻辑(清点商品/计算价目/结算/送货上门)设计完成

2)再实现各模块小步骤。

3)不能确实的步骤,作为虚拟方法,甩锅给子类实现。

4)子类只需要聚焦自己的小步骤逻辑。 

二、测试代码:

1、结算过程抽象的父类

/**
 * 模板方法模式
 * 购物车费用结算过程
 */
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);

}

2、 会员卡结算方式:

/**
 * 模板方法模式
 * 购物车费用结算过程
 */
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);
    }
}

3、现金结算方式:

/**
 * 模板方法模式
 * 购物车费用结算过程
 */
public class CashShopping extends ShoppingCart{


    public CashShopping(List<Fruit> products) {
        super(products);
    }

    @Override
    protected void pay(int money) {
        System.out.println("现金结算,假一罚十");
    }
}

4、线上支付方式:

/**
 * 模板方法模式
 * 购物车费用结算过程
 */
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();

    }
}

5、他人代付方式:

/**
 * 模板方法模式
 * 购物车费用结算过程
 */
public class OtherPayShopping extends ShoppingCart{


    public OtherPayShopping(List<Fruit> products) {
        super(products);
    }

    @Override
    protected void pay(int money) {
        System.out.println("代付成功");
    }

}

6、客户端结算过程:

/**
 * 模板方法模式
 * 订单费用结算过程
 */
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 OtherPayShopping(products);

        //注入优惠方案
//        String discount = "second";
//        cart.setDiscount(disCounts.get(discount));

        cart.submitOrder();
    }

}

7、执行结果:

java 如何画方案图 java方案设计_模板方法模式_04

到此,模板方法设计模式分析完成