Java设计模式(十三/十四)行为型- 模板与策略模式(史上最全行为型模式模板策略模式)与使用场景以及优缺点

1.模板方法模式(Template method pattern)

模板方法模式通常又叫模板模式,是指定义一个算法的骨架,并允许之类为其中的一个或者多个步骤提供实现。模板方法模式使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤

模板方法(Template Method)模式包含以下主要角色:

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
  • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
  • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
  • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
  • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
  • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

1.1 代码实现

下面以一个简单的请假流程来通过代码来实现:

public abstract class DayOffProcess {
    // 请假模板
    public final void dayOffProcess() {
        // 领取申请表
        this.pickUpForm();
        // 填写申请信息
        this.writeInfo();
        // 签名
        this.signUp();
        // 提交到不同部门审批
        this.summit();
        // 行政部备案
        this.filing();
    }
    private void filing() {
        System.out.println("行政部备案");
    }
    protected abstract void summit();
    protected abstract void signUp();
    private void writeInfo() {
        System.out.println("填写申请信息");
    }
    private void pickUpForm() {
        System.out.println("领取申请表");
    }
}
public class ZhangSan extends DayOffProcess {
    @Override
    protected void summit() {
        System.out.println("张三签名");
    }
    @Override
    protected void signUp() {
        System.out.println("提交到技术部审批");
    }
}
public class Lisi extends DayOffProcess {
    @Override
    protected void summit() {
        System.out.println("李四签名");
    }
    @Override
    protected void signUp() {
        System.out.println("提交到市场部审批");
    }
}
    // 测试方法
    public static void main(String[] args) {
        DayOffProcess zhangsan = new ZhangSan();
        //领取申请表
        //填写申请信息
        //提交到技术部审批
        //张三签名
        //行政部备案
        zhangsan.dayOffProcess();
        DayOffProcess lisi = new Lisi();
        //领取申请表
        //填写申请信息
        //提交到市场部审批
        //李四签名
        //行政部备案
        lisi.dayOffProcess();
    }

1.2 总结

适用场景:

  • 一次性实现一个算法不变的部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复。

优点:

  • 利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
  • 将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提高代码的扩展性。
  • 把不变的行为写在父类上,去除子类的重复代码,提供了一个很好的代码复用平台,符合开闭原则。

缺点:

  • 类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加。
  • 类数量的增加,间接地增加了系统实现的复杂度。
  • 继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍。

2.策略模式(Strategy Pattern)

策略模式又叫政策模式(Policy Pattern),它是将定义的算法家族分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。可以避免多重分支的if…else和switch语句。

策略模式的主要角色如下:

抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
环境(Context)类:持有一个策略类的引用,最终给客户端调用。

2.1 普通案例(会员卡打折)

// 会员卡接口
public interface VipCard {
    public void discount();
}
public class GoldCard implements VipCard {
    @Override
    public void discount() {
        System.out.println("金卡打7折");
    }
}
public class SilverCard implements VipCard {
    @Override
    public void discount() {
        System.out.println("银卡打8折");
    }
}
public class CopperCard implements VipCard {
    @Override
    public void discount() {
        System.out.println("铜卡打9折");
    }
}
public class Normal implements VipCard {
    @Override
    public void discount() {
        System.out.println("普通会员没有折扣");
    }
}
// 会员卡容器类
public class VipCardFactory {
    private static Map<String, VipCard> map = new ConcurrentHashMap<>();
    static {
        map.put("gold", new GoldCard());
        map.put("silver", new SilverCard());
        map.put("copper", new CopperCard());
    }
    public static VipCard getVIPCard(String level) {
        return map.get(level) != null ? map.get(level) : new Normal();
    }
 
}
    // 测试方法
    public static void main(String[] args) {
        //金卡打7折
        VipCardFactory.getVIPCard("gold").discount();
        //银卡打8折
        VipCardFactory.getVIPCard("silver").discount();
        //普通会员没有折扣
        VipCardFactory.getVIPCard("other").discount();
    }

用一个容器(Map)装起来,可以通过传进来的参数直接获取对应的策略,避免了if…else。

2.2 支付方式案例

// 支付方式抽象类
public abstract class Payment {
    public String pay(String uid, double money) {
        double balance = queryBalance(uid);
        if (balance < money) {
            return "支付失败!余额不足!欠" + (money - balance) + "元!";
        }
        return "支付成功!支付金额:" + money + "余额剩余:" + (balance - money);
    }
    protected abstract String getPaymentName();
    protected abstract double queryBalance(String uid);
}
// 现金支付 默认方式
public class Cash extends Payment{
    @Override
    protected String getPaymentName() {
        return "现金支付";
    }
    @Override
    protected double queryBalance(String uid) {
        return 1000;
    }
}
// 支付宝类
public class AliPay extends Payment {
 
    @Override
    protected String getPaymentName() {
        return "支付宝";
    }
 
    @Override
    protected double queryBalance(String uid) {
        return 500;
    }
}
// 微信支付类
public class WeChatPay extends Payment {
    @Override
    protected String getPaymentName() {
        return "微信支付";
    }
 
    @Override
    protected double queryBalance(String uid) {
        return 300;
    }
}
// 支付方式容器策略类
public class PaymentStrategy {
    private static Map<String, Payment> map = new ConcurrentHashMap<>();
    static {
        map.put("WeChat", new WeChatPay());
        map.put("Ali", new AliPay());
    }
    public static Payment getPayment(String payment) {
        return map.get(payment) == null ? new Cash() : map.get(payment);
    }
 
}
// 订单交易类
@AllArgsConstructor
public class Order {
    private String uid;
    private double amount;
    public String pay() {
        return pay("cash");
    }
    public String pay(String key) {
        Payment payment = PaymentStrategy.getPayment(key);
        System.out.println("欢迎使用" + payment.getPaymentName());
        System.out.println("本次交易金额:" + this.amount + ",开始扣款...");
        return payment.pay(this.uid, this.amount);
    }
}
    // 测试方法
    public static void main(String[] args) {
        Order order = new Order("20221014001", 500);
        //欢迎使用微信支付
        //本次交易金额:500.0,开始扣款...
        //支付失败!余额不足!欠200.0元!
        System.out.println(order.pay("WeChat"));
        //欢迎使用支付宝
        //本次交易金额:500.0,开始扣款...
        //支付成功!支付金额:500.0余额剩余:0.0
        System.out.println(order.pay("Ali"));
        //欢迎使用现金支付
        //本次交易金额:500.0,开始扣款...
        //支付成功!支付金额:500.0余额剩余:500.0
        System.out.println(order.pay());
    }

2.3 总结

适用场景:

  • 系统中有很多类,而它们的区别仅仅在于它们的行为不同。
  • 系统需要动态地在几种算法中选择一种。
  • 需要屏蔽算法规则。

优点:

  • 符合开闭原则。
  • 避免使用多重条件语句。
  • 可以提高算法的保密性和安全性。
  • 易于扩展。

缺点:

  • 客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
  • 代码中会产生非常多的策略类,增加维护难度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘了个刘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值