探询策略模式
策略模式
定义:又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户(此处应该有图)
目的:让算法和对象分开;算法可以互相替换
注明:环境类封装未确定算法的使用,算法接口和算法具体实现类则构成了算法类层次。
优点:
- 算法类层次定义了一系列可供重用的算法或行为,使算法结构清晰化(对算法类本身有好处)
- 把算法封装在独立的算法类中,独立于环境类,可以易于切换,理解,拓展(对于算法类和环境类的搭配有好处)
- 消除了if-else条件语句
- 对于实现一个算法有更多的选择
策略模式Demo
策略环境类
/**
* 策略模式环境类
*
* @author Jax
*
*/
public class StrategyContext {
StrategyInterface strategy;
public StrategyContext(StrategyInterface strategy) {
this.strategy = strategy;
};
public void setStrategy(StrategyInterface strategy) {
this.strategy = strategy;
};
public String applyAlgorithm() {
return strategy.algorithm();
}
}
策略接口类
/**
* 策略接口
*
* @author Jax
*
*/
public interface StrategyInterface {
// 策略算法
String algorithm();
}
策略实现类A
public class ConcreteStrategyA implements StrategyInterface {
@Override
public String algorithm() {
// 这是具体策略A的算法
return "策略A";
}
}
策略实现类B
public class ConcreteStrategyB implements StrategyInterface {
@Override
public String algorithm() {
// 这是具体策略B的算法
return "策略B";
}
}
测试类的实现
public class Test {
public static void main(String[] args) {
//策略A的输出
StrategyContext context = new StrategyContext(new ConcreteStrategyA());
output(context.applyAlgorithm());
//策略B的输出
context.setStrategy(new ConcreteStrategyB());
output(context.applyAlgorithm());
//用匿名类输出
context.setStrategy(new StrategyInterface() {
@Override
public String algorithm() {
// TODO Auto-generated method stub
return "策略,匿名类";
}
});
output(context.applyAlgorithm());
}
// 输出结果
public static void output(String result) {
System.out.println("algorithm result:" + result);
}
}
当一个具体策略只被用来使用一次时,也可以使用匿名类来声明和实例化这个具体策略类。
测试结果:
algorithm result:策略A
algorithm result:策略B
algorithm result:策略,匿名类
单例策略
描述:当一个具体策略是被设计用来重复使用时,它的类通常实现为私有的静态成员类,然后通过公有的静态final域被导出,其类型为该策略接口。这样可以提高性能(如果程序经常请求创建相同的对象,并且创建对象的代价很高,那么用静态final域来表示这个对象则可以提高程序的性能)。
单例策略Demo
/**
* 具体策略单例
*
* @author Jax
*
*/
public class ConcreteSrategySingletonHost {
private static class StrategyImpl implements StrategyInterface {
@Override
public String algorithm() {
// TODO Auto-generated method stub
return "策略,单例";
}
}
public static final StrategyImpl THE_STRATEGY = new StrategyImpl();
}
测试类:
public class Test {
public static void main(String[] args) {
//静态单例策略的输出
StrategyContext context2 = new StrategyContext(ConcreteSrategySingletonHost.THE_STRATEGY);
output(context2.applyAlgorithm());
}
// 输出结果
public static void output(String result) {
System.out.println("algorithm result:" + result);
}
}
输出结果:
algorithm result:策略,单例
泛型策略
描述:泛型的使用可以在编译前就有效减少类转换异常的发生,使类或方法的实现变得简单安全。描述算法的策略常常用到了泛型单例工厂,这样可以对于一个未知的类进行操作,并且可以用对泛型的修饰来控制这个类的范围。
泛型策略Demo
带泛型的策略接口类
public interface GenericStrategy<T> {
// 这个接口设计仅作为一个最简单的例子
T apply(T arg);
}
具体策略类,泛型单例工厂
public class GenericStategySingletonHost {
private static GenericStrategy<Object> THE_STRATEGY = new GenericStrategy<Object>() {
@Override
public Object apply(Object arg) {
// 这只是一个最简单的例子,这里应是泛型单例的具体操作,用Obj对象代替泛型对象
return arg;
}
};
// 这里之所以可以消除非受检警告,是我们必须确定apply算法实现的时候不会出现类型转换异常
@SuppressWarnings("unchecked")
public static <T> GenericStrategy<T> getTheStrategy() {
return (GenericStrategy<T>) THE_STRATEGY;
}
}
测试类
public class Test {
public static void main(String[] args) {
GenericStrategy<String> stringGenericStrategy = GenericStategySingletonHost.getTheStrategy();
String stringArg = "String参数";
output("————泛型算法,泛型为String————结果为:" + stringGenericStrategy.apply(stringArg));
GenericStrategy<Integer> integerGenericStrategy = GenericStategySingletonHost.getTheStrategy();
Integer intergerArg = 1;
output("————泛型算法,泛型为Interger————结果为:" + integerGenericStrategy.apply(intergerArg));
if (stringGenericStrategy.equals(integerGenericStrategy)) {
output("————说明泛型为String的泛型算法对象和泛型为Interger的泛型算法对象是同一个————");
}
}
// 输出结果
public static void output(String result) {
System.out.println("algorithm result:" + result);
}
}
输出结果:
algorithm result:————泛型算法,泛型为String————结果为:String参数
algorithm result:————泛型算法,泛型为Interger————结果为:1
algorithm result:————说明泛型为String的泛型算法对象和泛型为Interger的泛型算法对象是同一个————
结语
本文第一节,介绍设计模式中第18条,策略模式。策略是什么?策略代表一个行为,也可以说它是一个函数。它可以针对输入的参数进行计算,进行修改,或者进行比较来输出结果。不同业务需求下,可能对应了不同的策略方式,如果我们用if-else来做处理,或者把不同的策略都写到同一个类中,会造成代码的混杂和逻辑层次的混乱。所以我们可以将不同策略具体实现抽象提炼成策略接口。这样我们就可以把 策略具体实现类和调用策略的环境类分开,类优化代码和逻辑关系。
本文第二节,介绍的是策略的单例实现。这是一种针对策略模式的优化方案。对于重复使用的策略,这种方式可以避免重复创建具体策略类对象。来改进代码的性能。
本文第三节,介绍的是策略单例实现+泛型单例工厂。泛型大家并不陌生,但是对于泛型的细致的使用可能也并不熟悉。所以对这一节的原理的理解会比较有难度。为什么例子中对于泛型策略接口方法的实现用Object来代替E呢?为什么这里测试代码的输出结果和参数一模一样呢,这样有什么意义呢?为什么两个不同泛型的策略对象实际上是同一个对象呢?
这里先回答关于Demo的设计。即解释测试代码中输出结果和参数一模一样的意义是什么。
首先,Demo中对于带泛型的策略接口方法的设计,十分的简单。其实,通过对泛型的修饰,比如多个泛型,泛型必须继承的父类,泛型必须的被继承的子类等,都可以通过代码进行描述,参数和返回结果都会十分多变复杂。这取决于策略意图本身。我这里只是举了个最简单的栗子,即输入什么类型,我返回什么类型。
其次,Demo中对于带泛型的策略接口的实现,也非常的简单。过程是在接口方法的限制下,是对于任意对象的任意操作。鉴于这只是个Demo,我取了最简单的实现方法,即什么都没做——就把这个参数原封不动地返回出去了而已。
所以,在Demo的测试类下,我们看到的结果只是参数的简单输出而已。其实,在这个过程中,有太多可以改变的地方。
最后,这个Demo想表达的意思,还有一个,在泛型不同的情况下,策略依然可以用单例来优化性能。最后一个输出结果我们可以看出,泛型不同的两个策略方法,其实都是那个单例而已,它并没有改变。