Strategy策略模式

本文介绍了策略模式在解决多方案选择问题中的应用,以商场打折促销为例,展示了如何通过重构将复杂的if分支逻辑转化为可扩展的策略设计。重构前的代码将各种打折方案集中在单一类中,不符合开闭原则,而重构后的代码将每个打折策略抽象为独立类,提高了代码的灵活性和复用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

策略模式定义

策略模式(Strategy),就是一个问题有多种解决方案,选择其中的一种使用,这种情况下我们 使用策略模式来实现灵活地选择,也能够方便地增加新的解决方案。
比如做数学题,一个问题的解法可能有多种;再比如商场的打折促销活动,打折方案也有很多种,有些商品是不参与折扣活动,要按照原价销售,有些商品打8.5折,有些打6折,有些是返现5元等。

结构

策略(Strategy)

定义所有支持算法的公共接口。 Context 使用这个接口来调用某 ConcreteStrategy 定义的算法。

策略实现(ConcreteStrategy)

实现了Strategy 接口的具体算法。

上下文(Context)

维护一个 Strategy 对象的引用,用一个 ConcreteStrategy 对象来装配,可定义一个接口方法让 Strategy 访问它的数据。

示例

假如现在有一个商场优惠活动,有的商品原价售卖,有的商品打8.5折,有的商品打6折,有的返现 5元。

重构前

package designpattern.strategy.old;

import java.text.MessageFormat;

public class BuyGoods {
    private String goods;
    private double price;
    private double finalPrice;
    private String desc;
    
    public BuyGoods(String goods, double price) { 
        this.goods = goods;
        this.price = price;
    }
    
    public double calculate(String discountType) { 
        if ("discount85".equals(discountType)) {
            finalPrice = price * 0.85;
            desc = "该商品可享受8.5折优惠";
        } else if ("discount6".equals(discountType)) {
            finalPrice = price * 0.6;
            desc = "该商品可享受6折优惠";
        } else if ("return5".equals(discountType)) {
            finalPrice = price >= 5 ? price - 5 : 0;
            desc = "该商品可返现5元"; 
        } else {
            finalPrice = price;
            desc = "对不起,该商品不参与优惠活动"; 
        }
        System.out.println(MessageFormat.format("您购买的商品为:{0},原价为: {1},{2},最终售卖价格为:{3}", goods, price, desc, finalPrice));
        return finalPrice;
    }
}

测试:

package designpattern.strategy.old;

public class Test {

    public static void main(String[] args) {
        BuyGoods buyGoods1 = new BuyGoods("Java编程思想", 99.00); 
        buyGoods1.calculate("discount85");
        BuyGoods buyGoods2 = new BuyGoods("罗技鼠标", 66 ); 
        buyGoods2.calculate("discount6");
        BuyGoods buyGoods3 = new BuyGoods("苹果笔记本", 15000.00); 
        buyGoods3.calculate("return5");
        BuyGoods buyGoods4 = new BuyGoods("佳能相机", 1900);
        buyGoods4.calculate(null); 
    }
}

上述代码可以解决问题,但是从代码设计的⻆度还是存在一些问题:

  • 增加或者修改打折方案时必须修改 BuyGoods 类源代码,违反了面向对象设计的 “开闭原则”,代码的灵活性和扩展性较差。
  • 打折方案代码聚合在一起,如果其他项目需要重用某个打折方案的代码,只能复制粘贴对应代码,无法以类组件的方式进行重用,代码的复用性差。
  • BuyGoods类的 calculate() 方法随着优惠方案的增多会非常庞大,代码中会出现很多if分支,可维护性差。

此时,我们可以使用策略模式对 BuyGoods 类进行重构,将打折方案逻辑(算法)的定义和使用分离。

重构后

抽象策略类 AbstractDiscount,它是所有具体打折方案(算法)的父类,定义了一个 discount 抽象方法。

package designpattern.strategy.now.discount;

public abstract class AbstractDiscount {
    
    protected double finalPrice;
    protected String desc;
    
    public IDiscount(String desc) { 
        this.desc = desc;
    }
    
    public abstract double discount(double price);
    
    public double getFinalPrice() {
        return finalPrice;
    }
    
    public void setFinalPrice(double finalPrice) { 
        this.finalPrice = finalPrice;
    }
    
    public String getDesc() {
        return desc;
    }
    
    public void setDesc(String desc) { 
        this.desc = desc;
    }
}

四种具体策略类,继承自抽象策略类 AbstractDiscount,并在 discount 方法中实现具体的打折方案(算法)。

package designpattern.strategy.now.discount.impl;
import designpattern.strategy.now.discount.AbstractDiscount;
 
public class Discount85 extends AbstractDiscount {
    
    public Discount85() {
        super("该商品可享受8.5折优惠"); 
    }
    
    @Override
    public double discount(double price) { 
        finalPrice = price * 0.85;
        return finalPrice;
    } 
}
package designpattern.strategy.now.discount.impl;
import designpattern.strategy.now.discount.AbstractDiscount;

public class Discount6 extends AbstractDiscount {
    
    public Discount6() {
        super("该商品可享受6折优惠"); 
    }
    
    @Override
    public double discount(double price) { 
        finalPrice = price * 0.6;
        return finalPrice;
    } 
}
package designpattern.strategy.now.discount.impl;
import designpattern.strategy.now.discount.AbstractDiscount;

public class Return5 extends AbstractDiscount {
    public Return5() {
        super("该商品可返现5元"); 
    }

    @Override
    public double discount(double price) { 
        this.finalPrice = price >= 5 ? price - 5 : 0; 
        return finalPrice;
    } 
}
package designpattern.strategy.now.discount.impl;
import designpattern.strategy.now.discount.AbstractDiscount;

public class NoDiscount extends AbstractDiscount {
    
    public NoDiscount() {
        super("对不起,该商品不参与优惠活动"); 
    }

    @Override
    public double discount(double price) { 
        finalPrice = price;
        return finalPrice;
    } 
}

类 BuyGoods,维护了一个 AbstractDiscount 引用:

package designpattern.strategy.now;
import designpattern.strategy.now.discount.AbstractDiscount; 
import java.text.MessageFormat;

public class BuyGoods {
    
    private String goods;
    private double price;
    private AbstractDiscount abstractDiscount;
    
    public BuyGoods(String goods, double price, AbstractDiscount abstractDiscount) {
        this.goods = goods;
        this.price = price;
        this.abstractDiscount = abstractDiscount;
    }
    
    public double calculate() {
        double finalPrice = abstractDiscount.discount(this.price);
        String desc = abstractDiscount.getDesc(); 
        System.out.println(MessageFormat.format("商品:{0},原价:{1},{2},最终价格为:{3}", goods, price, desc, finalPrice)); 
        return finalPrice;
    } 
}

测试:

package designpattern.strategy.now;
import designpattern.strategy.now.discount.impl.*;

public class Test {
    
    public static void main(String[] args) {
        BuyGoods buyGoods1 = new BuyGoods("Java编程思想", 99.00, new Discount85());
        buyGoods1.calculate();
        BuyGoods buyGoods2 = new BuyGoods("罗技鼠标", 66, new Discount6());
        buyGoods2.calculate();
        BuyGoods buyGoods3 = new BuyGoods("苹果笔记本", 15000.00, new Return5());
        buyGoods3.calculate();
        BuyGoods buyGoods4 = new BuyGoods("佳能相机", 1900, new NoDiscount());
        buyGoods4.calculate(); 
    }
}

重构后优点:

  • 增加新的优惠方案时只需要继承抽象策略类即可,修改优惠方案时不需要修改BuyGoods类源码;
  • 代码复用也变得简单,直接复用某一个具体策略类即可;
  • BuyGoods类的calculate变得简洁,没有了原本的if分支;

文章内容输出来源:拉勾教育Java高薪训练营

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jason559

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

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

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

打赏作者

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

抵扣说明:

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

余额充值