设计模式之strategy策略模式

1.意图

   Strategy模式不只是封装一系列可以互相提华纳的算法逻辑,使得具体的算法的演化独立于使用它们的客户端代码,而且我们不应该只着眼“算法”一词。实际上,只要能够有效地剥离客户端代码与特定关注点之间的依赖关系,Strategy模式都应该进入考虑之列。只要针对同一件事情有多种选择的时候,都可以考虑用Strategy模式来统一一下抽象接口。

2.类图

其中一个Composition类负责维护和更新一个正文浏览程序中显示的正文换行。换行策略不是Composition类实现的,而是由抽象的Compositor类的子类各自独立地实现的。

Compositor各个子类实现不同的换行策略:

  • SimpleCompositor 实现一次确定一个换行位置
  • TeXCompositor 实现一次处理一段文字的换行
  • ArrayCompositor 实现每一行都含有一个固定数目的项,用于对一系列图标进行分行。

Composition维护队Compositor对象的一个引用。一旦Composition重新格式化它的正文,他就将这个职责发给它的Compositor对象。Composition的客户指定应该使用那一种 Compositor的方式是直接将它想要的Compositor装入Composition中。

3.适用性

(1)许多相关的类仅仅是行为有异。

(2)使用一个算法的不同变体。

(3)算法使用客户不应该知道的数据。

(4)一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

5.结构

6 参与者

Strategy(策略,如Compositor)- 定义所有支持的算法的公共接口。Context使用这个接口调用某个具体的ConcreteStrategy定义的算法。

ConcreteStrategy(具体策略,如SimpleCompositor,TeXCompositor,ArrayCompositor)- 以Strategy接口实现某具体算法。

Context(上下文,如Composition)

   - 用一个ConcreteStrategy对象来配置。

   - 维护一个对Strategy对象的引用。

  - 可定义一个接口来让Strategy访问它的数据。

7 协作

  • Strategy和Context相互作用以实现选定的算法。
  • Context将它的客户请求转发给它的Strategy。客户通常创建并传递一个ConcreteStrategy对象给该Context;客户仅与Context交互。通常有一系列的ConcreteStrategy类可供客户从中选择。

 

8 实现

这里以不同的用户买商品打折为例
首先定义一个抽象算法接口:
//抽象算法接口:定义了所有支持算法的公共接口
public interface Strategy {
    //算法方法:打印商品的价格(不同的实现打不同的折扣)
    public double getPrice(double price);
}

 

然后定义具体的各个算法
//具体的算法:普通用户,不打折
public class GeneralUser implements Strategy {
    @Override
    public double getPrice(double price) {
        System.out.println("普通用户,不打折");
        return price;
    }
}
//具体的算法:注册用户:打9折
public class RegisterUser implements Strategy{
    @Override
    public double getPrice(double price) {
        System.out.println("注册用户:打9折");
        return price*0.9;
    }
}
//具体的算法:普通会员:打8折
public class RegisterVip implements Strategy{
    @Override
    public double getPrice(double price) {
        System.out.println("普通会员:打8折");
        return price*0.8;
    }
}
//具体的算法:老会员:打5折
public class OldVip implements Strategy{
    @Override
    public double getPrice(double price) {
        System.out.println("老会员:打5折");
        return price*0.5;
    }
}

 

接下来开始定义一个上下文,用来维护不同用户不同的折扣。
//上下文:用来维护不同对象的不同折扣
public class Context {
    private Strategy strategy;//持有算法族的引用
    public Context(Strategy strategy) {
        super();
        this.strategy = strategy;
    }
    //打印价钱
    public void printPrice(double price){
        System.out.println("应付金额:"+Math.round(strategy.getPrice(price)));
    }
}

 

客户端测试代码:
public static void main(String[] args) {
    double price = 998;//商品价格
    Strategy generalUser = new GeneralUser();//普通用户
    Strategy registerUser = new RegisterUser();//注册用户
    Strategy registerVip = new RegisterVip();//普通会员
    Strategy oldVip = new OldVip();//老会员
     
    //根据不同的用户打不同的折扣
    Context c1 = new Context(generalUser);
    c1.printPrice(price);
    Context c2 = new Context(registerUser);
    c2.printPrice(price);
    Context c3 = new Context(registerVip);
    c3.printPrice(price);
    Context c4 = new Context(oldVip);
    c4.printPrice(price);
}

 

打印结果如下:
                    普通用户,不打折
                    应付金额:998
                    注册用户:打9折
                    应付金额:898
                    普通会员:打8折
                    应付金额:798
                    老会员:打5折
                    应付金额:499

 

posted @ 2019-05-06 16:03  tiger5  阅读(156)  评论(0)    收藏  举报