欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式之策略模式

程序员文章站 2022-06-13 12:51:27
...

设计模式之策略模式

基本定义

指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

策略设计模式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/