设计模式之策略模式
设计模式之策略模式
基本定义
指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
策略设计模式UML图
- 环境(Context):持有一个Strategy的引用。
- 抽象策略(Strategy):抽象角色,通常是一个接口或者抽象类。给出所有的具体策略类所需要的接口方法。
- 具体策略(ConcreteStrategy):包装了相关的算法或行为。
在接口中定义了一系列算法,并将每个算法的具体实现封装起来,外部引用的是抽象接口。
使用场景
比如每个人都需要交个人所得税,但是在美国交个人所得税和在中国交个人所得税会有不同的算法。
正常实现可能就是if..else判断不同是美国还是中国,然后使用不同的算法。
使用策略模式就可以很好的解决这个问题。
场景
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别。
- 需要安全地封装多种同一类型的操作。
- 出现同一抽象类有多个子类,而有需要使用if-else或者switch-case来选择具体子类。
Java策略模式典型代码
// 策略接口,实现具体策略的类实现这个方法
interface Strategy {
//策略方法
void execute();
}
//使用策略接口实现算法
class FirstStrategy implements Strategy {
public void execute() {
System.out.println("Called FirstStrategy.execute()");
}
}
class SecondStrategy implements Strategy {
public void execute() {
System.out.println("Called SecondStrategy.execute()");
}
}
// 传入具体策略对象,并维护策略接口对象的引用
class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void execute() {
this.strategy.execute();
}
}
//测试使用
class StrategyExample {
public static void main(String[] args) {
Context context;
// 使用不同策略的两种场景
context = new Context(new FirstStrategy());
context.execute();
context = new Context(new SecondStrategy());
context.execute();
}
}
使用实例
假设鹅厂推出了3种会员,分别为会员,超级会员以及金牌会员,还有就是普通玩家,
针对不同类别的玩家,购买《王者农药》皮肤有不同的打折方式,并且一个顾客每消费10000就增加一个级别,
那么我们就可以使用策略模式,因为策略模式描述的就是算法的不同,
这里我们举例就采用最简单的,以上四种玩家分别采用原价(普通玩家),九折,八折和七价的收钱方式。
实现方式:策略模式 + 简单工厂
步骤:
1.创建计算价格的策略接口
2.创建四种玩家具体策略实现类
3.创建客户类,在客户类完成玩家升级功能
相关类:
- CalPrice接口:计算价格策略接口
- Orignice类:普通玩家策略类,实现CalPrice接口
- Vip类:会员策略类,实现CalPrice接口
- SVip类:超级会员策略类,实现CalPrice接口
- GoldVip类:黄金会员,实现CalPrice接口
- Player类: 玩家
- CalPriceFactory类:简单工厂,根据Player返回不同策略对象。
- Cient类: 测试类
UML类图
Orignice,Vip等类实现CalPrice接口,重写calPrice方法,实现不同的逻辑。
CalPrice接口
/**
* Created by qianbingbing on 2018/7/24.
* 计算价格策略
*/
public interface CalPrice {
/**
* 根据原价返回一个价格
* @param orgnicePrice 原价
* @return 计算后的价格
*/
Double calPrice(Double orgnicePrice);
}
Orignice类
/**
* Created by qianbingbing on 2018/7/24.
* 普通玩家
*/
public class Orgnice implements CalPrice {
@Override
public Double calPrice(Double orgnicePrice) {
return orgnicePrice;
}
}
Vip类
/**
* Created by qianbingbing on 2018/7/24.
* 会员
*/
public class Vip implements CalPrice {
@Override
public Double calPrice(Double orgnicePrice) {
return orgnicePrice * 0.9;
}
}
SVip和GoldVip类实现方式一样,只不过比例不同而已,这里就不贴代码了。
Player类
/**
* Created by qianbingbing on 2018/7/24.
* 玩家
*/
public class Player {
/**
* 客户消费总额
*/
private Double totalAmount = 0D;
/**
* 单次客户消费金额
*/
private Double amount = 0D;
/**
* 客户计算价格的策略,初始都为原价
*/
private CalPrice calPrice = new Orgnice();
/**
* 购买皮肤
* @param amount 消费的金额
*/
public void buy(Double amount){
this.amount = amount;
totalAmount += amount;
//将策略的定制转移给策略工厂,将这部分责任分离出去
// calPrice = CalPriceFactory.getInstance().creatCalPrice(this);
calPrice = CalPriceFactory.createCalPrice(this);
}
public Double calLastAmount(){
return calPrice.calPrice(amount);
}
public Double getTotalAmount() {
return totalAmount;
}
}
CalPriceFactory类,简单工厂
/**
* Created by qianbingbing on 2018/7/24.
* 策略简单工厂
*/
public class CalPriceFactory {
/**
* 并私有构造,防止直接获取示例.
*/
private CalPriceFactory(){
}
/**
* 根据玩家的消费总金额产生相应的策略
* @param customer 玩家
* @return 价格策略
*/
public static CalPrice createCalPrice(Player customer){
CalPrice calPrice = new Orgnice();
if (customer.getTotalAmount() > 30000) {
calPrice = new GoldVip();
}else if(customer.getTotalAmount() > 20000){
calPrice = new Svip();
}else if(customer.getTotalAmount() > 10000){
calPrice = new Vip();
}
return calPrice;
}
}
Client类
/**
* Created by qianbingbing on 2018/7/24.
* 测试类
*/
public class Client {
public static void main(String[] args){
Player player = new Player();
player.buy(0d);
System.out.println("玩家购买0元商品,需要付钱:" + player.calLastAmount());
player.buy(5000d);
System.out.println("玩家购买5000元商品,需要付钱:" + player.calLastAmount());
player.buy(5000d);
System.out.println("玩家购买5000元商品,需要付钱:" + player.calLastAmount());
player.buy(100d);
System.out.println("玩家购买100元商品,需要付钱:" + player.calLastAmount());
player.buy(12000d);
System.out.println("玩家购买12000元商品,需要付钱:" + player.calLastAmount());
player.buy(12000d);
System.out.println("玩家购买12000元商品,需要付钱:" + player.calLastAmount());
player.buy(12000d);
System.out.println("玩家购买12000元商品,需要付钱:" + player.calLastAmount());
}
}
输出:
玩家购买0元商品,需要付钱:0.0
玩家购买5000元商品,需要付钱:5000.0
玩家购买5000元商品,需要付钱:5000.0
玩家购买100元商品,需要付钱:90.0
玩家购买12000元商品,需要付钱:9600.0
玩家购买12000元商品,需要付钱:8400.0
玩家购买12000元商品,需要付钱:8400.0
结合简单工厂使我们的策略模式灵活了一些,但是如果增加一个会员类别就需要对工厂修改,增加if-else判断,简单工厂的问题就是对修改开放。如果想避免这个问题可以使用注解来解决,使用注解来设置上限和下限,用来表示策略生效的区间,来解决总金额判断问题。
可以参考:https://blog.csdn.net/u012124438/article/details/70039943/