用Java实现策略模式

63 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的的第11天

为什么要使用策略模式

设想你正在给某家超市编写收银系统,要求该系统要根据当天的优惠策略来决定收费,比如:

  • 如果当天全场8折,那么结账时价格就要乘以0.8
  • 如果当天满100减20,那么结账时就要判断当前总价是否达到100元

我们可以很简单地写出第一版代码:

class Payment {
    public double pay(double price,String strategy) {
        switch (strategy) {
            case "20%off":
                return price * 0.8;
            case "100-20":
                return price >= 100 ? price - 20 : price;
            default:
                return price;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Payment payment = new Payment();
        double finalPrice;
        finalPrice = payment.pay(120, "20%off");
        System.out.println("收银:" + finalPrice);
        finalPrice = payment.pay(120, "100-20");
        System.out.println("收银:" + finalPrice);
    }
}

然而如果后面还有新的优惠策略的话,我们就不得不在Payment.pay方法的switch中多加几个case,这样违背了开闭原则,十分不优雅,而且一不小心容易破坏之前已经测试通过的部分。

这时候我们就希望能够将结账这个动作和优惠策略这两个部分解耦,结账的动作永远不会发生变化,当我们需要增改优惠策略时,只需要关注增改的那一部分即可,于是策略模式就呼之欲出。

定义

策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

模式结构

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

  1. 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  2. 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
  3. 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

image.png

代码实现

public class Main {
    public static void main(String[] args) {
        Context c = new Context();
        double price = 120;
        double finalPrice;

        Strategy discount = new Discount();
        c.setStrategy(discount);
        finalPrice = c.strategy(price);
        System.out.println("收银:" + finalPrice);
        
        Strategy manJian = new ManJian();
        c.setStrategy(manJian);
        c.strategy(price);
        System.out.println("收银:" + finalPrice);
    }
}

//抽象策略类
interface Strategy {
    public double strategy(double price);    //策略方法
}

//打八折
class Discount implements Strategy {
    @Override
    public double strategy(double price) {
        return price * 0.8;
    }
}

//满减
class ManJian implements Strategy {
    @Override
    public double strategy(double price) {
        return price >= 100 ? price - 20 : price;
    }
}

//环境类
class Context {
    private Strategy strategy;

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public double strategy(double price) {
        return strategy.strategy(price);
    }
}