java 策略模式 促销_设计模式之策略模式

本文介绍了Java中的策略模式,用于定义算法族并封装,使其互换不影响客户端。适用于多算法选择的情况,如系统中的各种促销活动。通过策略接口和实现类,实现了原价、打折、满减等促销策略,通过上下文类动态选择和应用促销策略。

0x01.定义与类型

定义:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化不会影响到使用算法的用户。

从一系列里抽象出不变的部分

策略模式是将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现,并使他们可以相互替换,从而导致客户端程序独立于算法的改变。

类型:行为型

0x02.适用场景

系统有很多类,而他们的区别仅仅在于他们的行为不同

一个系统需要动态地在几中算法中选择一种

通过条件语句在多个分支中选取一

0x03.优缺点

1.优点

开闭原则

避免使用多重条件转移语句

提高算法的保密性和安全性

2.缺点

客户端必须知道所以的策略类,并自行决定使用哪一个策略类

产生很多的策略类

0x04.相关的设计模式

策略模式和工厂模式:工厂是创建对象,而策略是具体实现。

策略模式和状态模式:使用策略,客户端是不关心具体状态的。

0x05.策略模式如何实现

1.继承-在父类中提供实现方法,子类通过继承获得父类中的行为

优点:简单易用,已有的类可以快速添加父类的方法

缺点:不具有灵活性,对未来的变更支持差,需要覆写子类的方法来提供新的行为

2.抽象方法-在父类中提供抽象方法,强迫子类实现自己的行为

优点:足够灵活。

缺点:每个子类都要实现一遍代码,即使相同的行为也不例外,代码重复,没有复用的代码。

3.组合-策略模式核心

解释:在类中增加一个私有域,引用另一个已有的类的实例,通过调用引用实例的方法从而获得新的功能,这种设计称作组合(复合)。

将行为抽象为接口,在父类中持有该接口,并由该接口代替接口飞行行为

优点:

足够灵活,复用代码,更易于维护

使用了组合,使架构更加灵活

富有弹性,可以较好的应对变化(开--闭原则)

正好的代码复用型(相对于继承)

消除大量的条件语句

缺点:

客户代码需要了解每个策略实现的细节

增加了对象的数目(维护困难)

4.注意

继承是重用代码的利器,但继承并不是最好的工具。

Favor composition over inheritance.(复合优于继承)

0x06.策略模式的实现

通过分离变化得出的策略接口Strategy

Strategy的实现类

客户程序中有一个Strategy

在客户程序中选择/组装正确的Strategy实现

dd7b0af4b39dfb507d63d7f79f019de9.png

1.使用策略模式实现超市促销

需求

原价返回

打折

满减~~~~

281a483b44742f2fad88cfb0873d3b67.png

策略类(IPromotionStrategy)定义

/**

* 促销策略类

*/

public interface IPromotionStrategy {

/**

* 计算逻辑

*/

BigDecimal promotionAlgorithm();

/**

* 存入价钱

* @param price

*/

void setPrice(BigDecimal price);

}

根据不同情况实现策略类

/**

* 原价

*/

public class CashNormal implements IPromotionStrategy{

private BigDecimal price;

@Override

public BigDecimal promotionAlgorithm() {

//原价返回

return this.price;

}

public void setPrice(BigDecimal price) {

this.price = price;

}

}

/**

* 打折

*/

public class CashRebate implements IPromotionStrategy {

private BigDecimal price = BigDecimal.ZERO;

private BigDecimal rate;

public CashRebate(BigDecimal rate) {

this.rate = rate;

}

@Override

public BigDecimal promotionAlgorithm() {

//TODO 打折逻辑实现

}

public void setPrice(BigDecimal price) {

this.price = price;

}

}

/**

* 满减

*/

public class CashReturn implements IPromotionStrategy {

private BigDecimal price;

private BigDecimal minPrice;

private BigDecimal subPrice;

public CashReturn(BigDecimal minPrice, BigDecimal subPrice) {

this.minPrice = minPrice;

this.subPrice = subPrice;

}

@Override

public BigDecimal promotionAlgorithm() {

//TODO 满减逻辑实现

}

public void setPrice(BigDecimal price) {

this.price = price;

}

}

创建打折上下文(PromotionContext), 维护使用促销模式

public class PromotionContext {

/**

* 策略实现类包

*/

private static final String PACKAGE_NAME = "org.ko.strategy.promotion";

/**

* 组合策略类

*/

private IPromotionStrategy promotionStrategy;

/**

* 获取促销后价钱

* @return

*/

public BigDecimal getPrice () {

return this.promotionStrategy.promotionAlgorithm();

}

/**

* 创建促销手段

* 这里使用反射维护实例对象, 相关知识这里不再介绍.

* @param code 对应促销模式编码

* @param args 对应促销参数

*/

public void newPromotion (Integer code, Object... args) {

//根据促销模式编码获取促销模式对应类名称

String clazz = PromotionType.findClazz(code);

try {

//通过反射获取促销模式的对象

this.promotionStrategy = (IPromotionStrategy)Class.forName(PACKAGE_NAME + "." + clazz)

.getDeclaredConstructor(getClasses(args)).newInstance(args);

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

/**

* 设置打折前的价格

* @param price

*/

public void setPrice (BigDecimal price) {

this.promotionStrategy.setPrice(price);

}

/**

* 获取Class

* @param args

* @return

*/

private Class[] getClasses (Object... args) {

Class[] classes = new Class[args.length];

for (int i = 0; i < args.length; i ++) {

classes[i] = args[i].getClass();

}

return classes;

}

}

创建枚举维护促销样例

/**

* 促销手段样例

*/

public enum PromotionType {

CashNormal(1, "CashNormal", "原价"),

CashRebate(2, "CashRebate", "打折"),

CashReturn(3, "CashReturn", "满减");

private Integer code;

private String clazz;

private String description;

PromotionType(Integer code, String clazz, String description) {

this.code = code;

this.clazz = clazz;

this.description = description;

}

/**

* 通过编码获取促销手段

* @param code 促销手段编码

* @return

*/

public static String findClazz(Integer code) {

for (PromotionType type : PromotionType.values()) {

if (Objects.equals(code, type.code)) {

return type.clazz;

}

}

return null;

}

}

测试与应用

public static void main(String[] args) {

//初始化上下文

PromotionContext context = new PromotionContext();

//测试无促销

context.newPromotion(1);

context.setPrice(new BigDecimal("200"));

BigDecimal price = context.getPrice();

System.out.println(price);

//测试打折

context.newPromotion(2, new BigDecimal("0.8"));

context.setPrice(new BigDecimal("200"));

price = context.getPrice();

System.out.println(price);

//测试满减

context.newPromotion(3, new BigDecimal("300"), new BigDecimal("100"));

context.setPrice(new BigDecimal("200"));

price = context.getPrice();

System.out.println(price);

context.setPrice(new BigDecimal("300"));

price = context.getPrice();

System.out.println(price);

}

策略模式总结篇

将一些方法抽象成接口

在基类中实例化接口

设置接口的私有成员变量

在积累中调用接口的同样方法

这样实现了代码的复用

面向接口编程,而不是面向实现编程,多用组合

适用场景

许多相关的类仅仅是行为差异

运行时选取不同的算法遍体

通过条件语句在多个分支中选取一

0x07.源码中的策略模式

Comparator, Arrays

TreeMap

Resource

0x08.代码地址

0x09.推荐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值