阅读 128

DesignPattern - 策略模式【行为型】

欢迎关注微信公众号:FSA全栈行动 👋

一、策略模式介绍

策略模式(Strategy Pattern)定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换

  • 核心组成

    • Context 上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
    • Strategy 策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
    • ConcreteStrategy 具体策略角色:用于实现抽象策略中的操作,即实现具体的算法
  • 应用场景

    • 外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
    • Java AWT 中的 LayoutManager(布局管理器)
    • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
    • 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
  • 优点

    • 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
    • 避免使用多重条件判断,如果不同策略模式可能会使用多重条件语句,不利于维护,和工厂模式搭配使用可以很好地消除 if-else 代码的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
  • 缺点

    • 策略类数量会增多,每个策略都是一个类,复用的可能性很小
    • 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀

补充:JDK 中的 Collections#sort(list, comparator) 就是策略模式,比较逻辑由外部传入决定。

二、策略模式代码实现

以电商促销为例,一件商品,平时 800 元,赶上国庆促销,有 3 种折扣方式供用户选择:

  • 不使用任何折扣
  • 使用 8 折折扣
  • 使用优惠券折扣

创建商品订单类:

/**
 * 商品订单类
 *
 * @author GitLqr
 */
public class ProductOrder {

	private float oldPrice;
	private int userId;
	private int productId;

	public ProductOrder(float oldPrice, int userId, int productId) {
		super();
		this.oldPrice = oldPrice;
		this.userId = userId;
		this.productId = productId;
	}

	... settter & getter ...
}
复制代码

创建抽象策略类,当前策略的目的就是计算出折扣后的价格:

/**
 * 抽象策略角色:活动策略
 *
 * @author GitLqr
 */
public abstract class ActivityStrategy {

	/**
	 * 计算订单价格
	 */
	public abstract double computePrice(ProductOrder productOrder);
}
复制代码

创建具体策略类,对应上面的 3 种折扣方式:

/**
 * 具体策略:没有活动
 *
 * @author GitLqr
 */
public class NormalActivityStrategy extends ActivityStrategy {

	@Override
	public double computePrice(ProductOrder productOrder) {
		return productOrder.getOldPrice();
	}
}

/**
 * 具体策略:打折活动
 *
 * @author GitLqr
 */
public class DiscountActivityStrategy extends ActivityStrategy {

	private float rate; // 折扣

	public DiscountActivityStrategy(float rate) {
		super();
		this.rate = rate;
	}

	@Override
	public double computePrice(ProductOrder productOrder) {
		return productOrder.getOldPrice() * rate;
	}
}

/**
 * 具体策略:优惠券抵扣活动
 *
 * @author GitLqr
 */
public class VoucherActivityStrategy extends ActivityStrategy {

	private float voucher;

	public VoucherActivityStrategy(float voucher) {
		super();
		this.voucher = voucher;
	}

	@Override
	public double computePrice(ProductOrder productOrder) {
		if (productOrder.getOldPrice() > voucher) {
			return productOrder.getOldPrice() - voucher;
		} else {
			return 0;
		}
	}
}
复制代码

创建上下文类:

说明:对外屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化

/**
 * 上下文:促销上下文
 *
 * @author GitLqr
 */
public class PromotionContext {
	// 持有具体策略
	private ActivityStrategy activityStrategy;

	public PromotionContext(ActivityStrategy activityStrategy) {
		super();
		this.activityStrategy = activityStrategy;
	}

	// 直接使用具体策略进行计算
	public double executeStrategy(ProductOrder productOrder) {
		return activityStrategy.computePrice(productOrder);
	}
}
复制代码

使用:

public static void main(String[] args) {

    ProductOrder productOrder = new ProductOrder(800, 9527, 1001);
    PromotionContext promotionContext;
    double finalPrice;

    // 没活动
    promotionContext = new PromotionContext(new NormalActivityStrategy());
    finalPrice = promotionContext.executeStrategy(productOrder);
    System.out.println("正常价:" + finalPrice);

    // 打折活动
    promotionContext = new PromotionContext(new DiscountActivityStrategy(0.8f));
    finalPrice = promotionContext.executeStrategy(productOrder);
    System.out.println("折扣价:" + finalPrice);

    // 使用优惠券抵扣
    promotionContext = new PromotionContext(new VoucherActivityStrategy(100));
    finalPrice = promotionContext.executeStrategy(productOrder);
    System.out.println("使用优惠券抵扣价:" + finalPrice);
}
复制代码

如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有Android技术, 还有iOS, Python等文章, 可能有你想要了解的技能知识点哦~

文章分类
代码人生
文章标签