策略模式

来源:互联网 发布:php音乐网站 编辑:程序博客网 时间:2024/05/22 05:25

实例场景

1、一位父亲有三个儿子,在临终签前告诉他们死后会留下的东西,分别给他们每人送了一个箱子,A儿子打开箱子需要解决一个问题能够拿到的是一栋别墅,B儿子打开箱子需要解决一个问题能够拿到的是一辆豪车,C儿子打开箱子需要解决一个问题能够拿到的是一笔巨款,在这个场景中我们用到了策略模式,下面详细说明。

2、在java的集合框架中,我们有多钟排序算法,只要用户想要哪种排序,生成相应的排序类,然后传入到Collection的sort参数中,就能够实现相应的排序规则,这里面用到了我们的策略模式。

策略模式

策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

策略模式的好处在于你可以动态的改变对象的行为。

设计原则

     设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。 策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。

策略模式中有三个对象
(1)       环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
(2)       抽象策略对象:它可由接口或抽象类来实现。
(3)       具体策略对象:它封装了实现同不功能的不同算法。
利用策略模式构建应用程序,可以根据用户配置等内容,选择不同有算法来实现应用程序的功能。具体的选择有环境对象来完成。采用这种方式可以避免由于使用条件语句而带来的代码混乱,提高应用程序的灵活性与条理性。

代码实现场景:

模拟场景1

package cn.com.strategy;//定义一个策略接口,这是父亲给三个儿子设计问题取得遗产的接口public interface IStrategy {//打开箱子,每个问题都是一个算法public void execute();}

package cn.com.strategy;//定义一个实现类,A儿子打开箱子,解决问题,得到一栋别墅public class ImplA implements IStrategy {@Overridepublic void execute() {System.out.println("解决问题,得到一栋别墅");}}

package cn.com.strategy;//定义一个实现类,B儿子打开箱子,解决问题,得到一栋豪车public class ImplB implements IStrategy {@Overridepublic void execute() {System.out.println("解决问题,得到一辆豪车");}}
package cn.com.strategy;//定义一个实现类,C儿子打开箱子,解决问题,得到一笔巨款public class ImplC implements IStrategy {@Overridepublic void execute() {System.out.println("解决问题,得到一笔巨款");}}
package cn.com.strategy;//定义一个环境对象,在场景中就像那个箱子public class Environment {private IStrategy iStrategy;//两种方法为其赋值,构造和set、getpublic Environment(IStrategy iStrategy){this.iStrategy=iStrategy;}public void execute(){iStrategy.execute();}}

package cn.com.strategy;//测试类,看似代码一样,但是传入不同的实现类,得到不同结果public class Test {public static void main(String[] args) {Environment e=new Environment(new ImplA());e.execute();//A儿子打开箱子解决问题,得到一栋别墅e=new Environment(new ImplB());e.execute();//B儿子打开箱子解决问题,得到一辆豪车e=new Environment(new ImplC());e.execute();//C儿子打开箱子解决问题,得到一笔巨款}}

输出结果将会是:

解决问题,得到一栋别墅 

解决问题,得到一辆豪车
解决问题,得到一笔巨款模拟场景2
package cn.com.strategy;import java.util.List;//定义一个排序的策略接口public interface SortStrategy<T> {public void sort(List<T> list);//执行排序算法}

package cn.com.strategy;import java.util.List;//定义一个实现类,实现冒泡排序public class SortBubble<T> implements SortStrategy<T> {@Overridepublic void sort(List<T> list) {System.out.println("实现冒泡排序算法");}}

package cn.com.strategy;import java.util.List;//定义一个实现类,实现堆排序public class SortHeap<T> implements SortStrategy<T> {@Overridepublic void sort(List<T> list) {System.out.println("实现堆排序算法");}}

package cn.com.strategy;import java.util.List;//定义一个实现类,实现快速排序public class SortQuick<T> implements SortStrategy<T> {@Overridepublic void sort(List<T> list) {System.out.println("实现快速排序算法");}}

package cn.com.strategy;import java.util.List;//定义一个环境对象,在场景中就是我们的算法使用者public class Sorter {private SortStrategy iStrategy;//两种方法为其赋值,构造和set、getpublic SortStrategy getiStrategy() {return iStrategy;}public void setiStrategy(SortStrategy iStrategy) {this.iStrategy = iStrategy;}//传入相应的算法,对其进行排序public void sort(List list){this.iStrategy.sort(list);}}

package cn.com.strategy;import java.util.ArrayList;import java.util.List;//测试类,看似代码一样,但是传入不同的排序实现类,得到不同的排序结果public class Test {public static void main(String[] args) {List list=new ArrayList();list.add(2);list.add(3);list.add(1);Sorter sort=new Sorter();SortBubble<Integer> sb=new SortBubble<Integer>();sort.setiStrategy(sb);//实现冒泡排序sort.setiStrategy(new SortHeap<Integer>());//实现堆排序sort.setiStrategy(new SortQuick<Integer>());//实现快速排序}}

输出相应的排序结果
在我们的集合框架中可以设计不同的Comparator来实现不同的比较方式,大大的提高了程序的扩展性,但值得说的类也要实现Comparable接口,只是在Comparable接口的实现方法中使用我们自己设置的排序策略,当然我们可以指定默认的排序算法,如上,这样如果有特殊需求时,在设置相应的排序算法,极大的提高了系统的灵活性。

策略模式优缺点

优点:

1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。

2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

简单工厂模式和策略模式区别(摘录,出处)

这两种模式的作用就是拥抱变化,减少耦合。在变化来临时争取做最小的改动来适应变化。这就要求我们把些“善变”的功能从客户端分离出来,形成一个个的功能类,然后根据多态特性,使得功能类变化的同时,客户端代码不发生变化。

简单工厂模式

简单工厂模式:有一个父类需要做一个运算(其中包含了不同种类的几种运算),将父类涉及此运算的方法都设成虚方法,然后父类派生一些子类,使得每一种不同的运算都对应一个子类。另外有一个工厂类,这个类一般只有一个方法(工厂的生成方法),这个方法的返回值是一个超类,在方法的内部,根据传入参数的不同,分别构造各个不同的子类的对象,并返回。客户端并不认识子类,客户端只认识超类和工厂类。每次客户端需要一中运算时,就把相应的参数传给工厂类,让工厂类构造出相应的子类,然后在客户端用父类接收(这里有一个多态的运用)。客户端很顺理成章地用父类的计算方法(其实这是一个虚方法,并且已经被子类特化过了,其实是调用子类的方法)计算出来结果。如果要增加功能时,你只要再从父类中派生相应功能的子类,然后修改下工厂类就OK了,对于客户端是透明的。

策略模式

策略模式:策略模式更直接了一点,没有用工厂类,而是直接把工厂类的生成方法的代码写到了客户端。客户端自己构造出了具有不同功能的子类(而且是用父类接收的,多态),省掉了工厂类。策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。这里的算法家族和简单工厂模式里的父类是同一个概念。当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为,将这些行为封装在一个个独立的策略子类中,可以在客户端中消除条件语句。

简单工厂模式+策略模式:为了将工厂方法的代码从客户端移出来,我们把这些代码搬到了父类的构造函数中,让父类在构造的时候,根据参数,自己实现工厂类的作用。这样做的好处就是,在客户端不用再认识工厂类了,客户端只要知道父类一个就OK,进一步隔离了变化,降低了耦合。

在基本的策略模式中,选择所用具体实现的职责由客户端对象成端,并转给客户端。这本身并没有减除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由父类承担,这就最大化地减轻了客户端的职责。

总结

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

原创粉丝点击