探询策略模式

来源:互联网 发布:淘宝买太多了会怎么样 编辑:程序博客网 时间:2024/05/22 10:27

探询策略模式


策略模式

定义:又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户(此处应该有图)

目的:让算法和对象分开;算法可以互相替换

注明:环境类封装未确定算法的使用,算法接口和算法具体实现类则构成了算法类层次。

优点

  1. 算法类层次定义了一系列可供重用的算法或行为,使算法结构清晰化(对算法类本身有好处)
  2. 把算法封装在独立的算法类中,独立于环境类,可以易于切换,理解,拓展(对于算法类和环境类的搭配有好处)
  3. 消除了if-else条件语句
  4. 对于实现一个算法有更多的选择

策略模式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:策略Aalgorithm result:策略Balgorithm 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————结果为:1algorithm result:————说明泛型为String的泛型算法对象和泛型为Interger的泛型算法对象是同一个————

结语

本文第一节,介绍设计模式中第18条,策略模式。策略是什么?策略代表一个行为,也可以说它是一个函数。它可以针对输入的参数进行计算,进行修改,或者进行比较来输出结果。不同业务需求下,可能对应了不同的策略方式,如果我们用if-else来做处理,或者把不同的策略都写到同一个类中,会造成代码的混杂和逻辑层次的混乱。所以我们可以将不同策略具体实现抽象提炼成策略接口。这样我们就可以把 策略具体实现类和调用策略的环境类分开,类优化代码和逻辑关系。

本文第二节,介绍的是策略的单例实现。这是一种针对策略模式的优化方案。对于重复使用的策略,这种方式可以避免重复创建具体策略类对象。来改进代码的性能。

本文第三节,介绍的是策略单例实现+泛型单例工厂。泛型大家并不陌生,但是对于泛型的细致的使用可能也并不熟悉。所以对这一节的原理的理解会比较有难度。为什么例子中对于泛型策略接口方法的实现用Object来代替E呢?为什么这里测试代码的输出结果和参数一模一样呢,这样有什么意义呢?为什么两个不同泛型的策略对象实际上是同一个对象呢?

这里先回答关于Demo的设计。即解释测试代码中输出结果和参数一模一样的意义是什么。

首先,Demo中对于带泛型的策略接口方法的设计,十分的简单。其实,通过对泛型的修饰,比如多个泛型,泛型必须继承的父类,泛型必须的被继承的子类等,都可以通过代码进行描述,参数和返回结果都会十分多变复杂。这取决于策略意图本身。我这里只是举了个最简单的栗子,即输入什么类型,我返回什么类型。

其次,Demo中对于带泛型的策略接口的实现,也非常的简单。过程是在接口方法的限制下,是对于任意对象的任意操作。鉴于这只是个Demo,我取了最简单的实现方法,即什么都没做——就把这个参数原封不动地返回出去了而已。

所以,在Demo的测试类下,我们看到的结果只是参数的简单输出而已。其实,在这个过程中,有太多可以改变的地方。

最后,这个Demo想表达的意思,还有一个,在泛型不同的情况下,策略依然可以用单例来优化性能。最后一个输出结果我们可以看出,泛型不同的两个策略方法,其实都是那个单例而已,它并没有改变。

0 0
原创粉丝点击