设计模式之策略模式(STRATEGY)

1.适用性

当存在以下情况时使用STRATEGY模式

a.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。

b.需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。

c.算法使用客户不应该知道的数据。可以使用策略模式以避免暴露复杂的、与算法相关的数据结构。

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

2.参与者

 Strategy(策略): 定义所有支持的算法的公共接口。Context使用这个接口来调用某种ConcreteStrategy定义的算法。

 ConcreteStrategy(具体策略):以Strategy接口实现某种具体算法。

 Context(上下文):用一个ConcreteStategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口让Strategy访问它的数据。

3.优缺点

 优点: 

a.相关算法系列:Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取算法中的公共的功能。

b.一个替代继承的方法:可以直接生成一个Context的子类,从而给它以不同的行为。但是,这会将行为硬编码到Context中,而将算法的实现和Context的实现混合起来,使得Context难以理解、维护和扩展,而且还不能动态的改变算法。

c.消除了一些条件语句:没有使用strategy模式的代码很有可能会被设计成在一个类中,使用if判断条件执行相应的策略。

d.实现的选择:客户端可以根据要求从不同的策略中进行选择。

 缺点:

a.Strategy和Context之间的通讯开销: 无论各个ConcreteStrategy实现的算法是简单还是复杂,他们都会共享Strategy定义的接口。因此很可能某些ConcreteStrategy不会都用到所有通过这个接口传递给他们的信息。简单的ConcreteStrategy可能不会使用其中的任何信息,这就意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这样的问题,那么将需要在Strategy和Context之间进行紧密的耦合。

b.增加了对象的数目

4.实例

package strategy;

/**
 * Description: 策略接口类
 *
 * @author 
 * @version 1.0
 * @since 2017-08-02 5:46 PM
 */
public interface Strategy {

    void algorithmInterface();
}

package strategy;

/**
 * Description: 具体策略A
 *
 * @author 
 * @version 1.0
 * @since 2017-08-02 5:47 PM
 */
public class ConcreteStrategyA implements Strategy {

    @Override
    public void algorithmInterface() {
        System.out.println("策略A执行");
    }
}

package strategy;

/**
 * Description: 具体策略B
 *
 * @author 
 * @version 1.0
 * @since 2017-08-02 5:48 PM
 */
public class ConcreteStrategyB implements Strategy {

    @Override
    public void algorithmInterface() {
        System.out.println("策略B执行");
    }
}

package strategy;

/**
 * Description: 具体策略C
 *
 * @author 
 * @version 1.0
 * @since 2017-08-02 5:49 PM
 */
public class ConcreteStrategyC implements Strategy {

    @Override
    public void algorithmInterface() {
        System.out.println("策略C执行");
    }
}

package strategy;

/**
 * Description: 上下文配置类
 *
 * @author yunqiangdi
 * @version 1.0
 * @since 2017-08-02 5:49 PM
 */
public class Context {

    //持有策略接口的引用
    private Strategy strategy;

    /**
     * 用其中某个策略初始化上下文
     * @param strategy 具体的策略类
     */
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    /**
     * 进行策略的具体执行
     */
    public void operator() {
        strategy.algorithmInterface();
    }
}

package strategy;

/**
 * Description: 策略测试类
 *
 * @author yunqiangdi
 * @version 1.0
 * @since 2017-08-02 5:55 PM
 */
public class StrategyTest {

    public static void main(String[] args) {
        Strategy strategy = new ConcreteStrategyA();
        Context ctx = new Context(strategy);
        ctx.operator();
    }
}


第二种表示策略的方式为使用匿名内部类表示策略(这种也可以把匿名内部类当作一个函数对象)。


package strategy.example2;

/**
 * @author koou
 * @version 1.0
 * @since 2017-08-05 下午 13:26
 */
public interface Strategy<T> {
    /**
     * 策略接口
     * @param t 策略执行
     */
    <T> void process(T t);
}

package strategy.example2;

/**
 * @author koou
 * @version 1.0
 * @since 2017-08-05 下午 13:27
 */
public class StrategyProcess {

    /**
     * @param t 策略的执行对象
     * @param strategy 具体策略
     */
    public static <T> void apply(T t, Strategy<T> strategy) {
        strategy.process(t);
    }

}


package strategy.example2;

import java.util.Arrays;

/**
 * @author koou
 * @version 1.0
 * @since 2017-08-05 下午 13:30
 */
public class StrategyTest {

    public static void main(String[] args) {
        int[] iarray = {1, 2, 3, 4, 5};
        //对int数组进行策略操作,修改数组第一个数字为9097
        StrategyProcess.apply(iarray, new Strategy<int[]>() {
            public <T> void process(T t) {
                int[] temparray = (int[]) t;
                if (temparray.length > 1) {
                    temparray[0] = 9097;
                }
            }
        });
        System.out.println(Arrays.toString(iarray));
    }
}


输出为:
[9097, 2, 3, 4, 5]


由匿名内部类每次执行的时候会创建一个新的实例,如果它被重复执行,考虑将函数对象存储到一个私有的静态final域中。


package strategy.example3;

import java.io.Serializable;
import java.util.Comparator;

/**
 * @author koou
 * @version 1.0
 * @since 2017-08-05 下午 17:03
 */
public class Host {

    private static class StrLenCmp implements Comparator<String>, Serializable {

        public int compare(String o1, String o2) {
            return o1.length() - o2.length();
        }
    }
    //具体的策略
    public static final Comparator<String> STRING_LEN_COMPARATOR = new StrLenCmp();


}


package strategy.example3;

import java.util.Arrays;

/**
 * @author koou
 * @version 1.0
 * @since 2017-08-05 下午 17:09
 */
public class StrategyTest {

    public static void main(String[] args) {
        String[] strArray = {"I", "am", "sk", "I"};
        Arrays.sort(strArray, Host.STRING_LEN_COMPARATOR);
        System.out.println(Arrays.toString(strArray));
    }
}

测试结果:[I, I, am, sk]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值