java设计模式之——策略模式
2015-10-08 16:00
661 查看
/content/2600599.html
java设计模式之——策略模式
设计模式Java算法
java设计模式之——策略模式
1,什么是策略模式?
策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
2,策略模式有什么好处?
策略模式的好处在于你可以动态的改变对象的行为。
3,设计原则
设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。
策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响 到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
4 ,策略模式中有三个对象:
(1) 环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
(2) 抽象策略对象:它可由接口或抽象类来实现。
(3) 具体策略对象:它封装了实现同不功能的不同算法。
利用策略模式构建应用程序,可以根据用户配置等内容,选择不同有算法来实现应用程序的功能。具体的选择有环境对象来完成。采用这种方式可以避免由于使用条件语句而带来的代码混乱,提高应用程序的灵活性与条理性。
5,应用场景举例:
刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开能解决棘手问题,嘿,还别说,真解决了大问题,搞到最后是周瑜陪了夫人又折兵,那咱们先看看这个场景是什么样子的。
先说说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是亮哥给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜。用java程序怎么表现这些呢?
那我们先来看看图?
三个妙计是同一类型的东西,那咱就写个接口:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 首先定义一个策略接口,这是诸葛亮老人家给赵云的三个锦囊妙计的接口。 */ public interface IStrategy { //每个锦囊妙计都是一个可执行的算法。 public void operate(); }
然后再写三个实现类,有三个妙计嘛:
妙计一:初到吴国:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 找乔国老帮忙,使孙权不能杀刘备。 */ public class BackDoor implements IStrategy { @Override public void operate() { System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备..."); } }
妙计二:求吴国太开个绿灯,放行:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 求吴国太开个绿灯。 */ public class GivenGreenLight implements IStrategy { @Override public void operate() { System.out.println("求吴国太开个绿灯,放行!"); } }
妙计三:孙夫人断后,挡住追兵:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 孙夫人断后,挡住追兵。 */ public class BlackEnemy implements IStrategy { @Override public void operate() { System.out.println("孙夫人断后,挡住追兵..."); } }
好了,大家看看,三个妙计是有了,那需要有个地方放妙计啊,放锦囊里:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * */ public class Context { private IStrategy strategy; //构造函数,要你使用哪个妙计 public Context(IStrategy strategy){ this.strategy = strategy; } public void operate(){ this.strategy.operate(); } }
然后就是赵云雄赳赳的揣着三个锦囊,拉着已步入老年行列,还想着娶纯情少女的,色咪咪的刘备老爷子去入赘了,嗨,还别说,亮哥的三个妙计还真不错,瞧瞧:
Java代码
package com.yangguangfu.strategy; public class ZhaoYun { /** * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 */ public static void main(String[] args) { Context context; //刚到吴国的时候拆开第一个 System.out.println("----------刚刚到吴国的时候拆开第一个---------------"); context = new Context(new BackDoor()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //当刘备乐不思蜀时,拆开第二个 System.out.println("----------刘备乐不思蜀,拆第二个了---------------"); context = new Context(new GivenGreenLight()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //孙权的小追兵了,咋办?拆开第三个锦囊 System.out.println("----------孙权的小追兵了,咋办?拆开第三个锦囊---------------"); context = new Context(new BlackEnemy()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); } }
后话:就这三招,搞得的周郎是“赔了夫人又折兵”呀!这就是策略模式,高内聚低耦合的特点也表现出来了,还有一个就是扩展性,也就是OCP原则,策略类可以继续添加下去气,只是修改Context.java就可以了,这个不多说了,自己领会吧。
http://zhanche2011.iteye.com/blog/1169948
Java策略模式(Strategy模式) 之体验
博客分类:
Java程序
设计模式
Java 策略模式Java设计模式Java
Strategy模式环境角色Context 作用
本文探讨初学使用策略模式时遇到的一些疑惑,以及在工作中慢慢解决之前遇到的疑惑,借此与大家分享。比如说本文谈到策略模式中环境角色Context的用处,为什么一定要用,可不可以将此取消。这些都是在学习和工作的实践总结中慢慢体会到的。
首先,我们来看下策略模式的概念。一般的解释如下:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)
一般的,策略模式主要分为以下三个角色:
1. 环境角色(Context):持有一个策略类引用
2. 抽象策略(Strategy):定义了多个具体策略的公共接口,具体策略类中各种不同的算法以不同的方式实现这个接口;Context使用这些接口调用不同实现的算法。一般的,我们使用接口或抽象类实现。
3. 具体策略(ConcreteStrategy):实现抽象策略类中的相关的算法或操作。
我们首先来写一个简单的策略模式,然后再结合实际应用进行扩展,进而思考其在实际开发中的使用方法。
(给大家推荐前辈写的一篇不错的博文,研磨设计模式之 策略模式http://www.uml.org.cn/sjms/201009092.asp)
我们这个简单的策略假设就是想让不同的策略来实现某个算法(algorithm),抽象类如下:
Java代码
package com.icecode.demo.strategy; /** * 抽象策略 * @author zhanche * */ public abstract class AbstractStrategy { /** * 某个希望有不同策略实现的算法 */ public abstract void algorithm(); }
算法algorithm的具体实现策略类ConcreteStrategy1和ConcreteStrategy2如下:
Java代码
package com.icecode.demo.strategy.impl; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm() { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm() { System.out.println("----------------我是策略二算法----------------"); } }
环境角色的实现如下:
Java代码
package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { private AbstractStrategy strategy; public Context(AbstractStrategy strategy) { this.strategy = strategy; } public void algorithm() { this.strategy.algorithm(); } }
下面简单写一个客户端测试的代码:
Java代码
package com.icecode.demo; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { Context context = new Context(new ConcreteStrategy1()); context.algorithm(); context = new Context(new ConcreteStrategy2()); context.algorithm(); } }
输出结果如下:
----------------我是策略一算法----------------
----------------我是策略二算法----------------
好吧,到此为止,一个简单的策略模式就写完了。但是,大家肯定有所疑惑,Context完全可以没有嘛,既然抽象策略AbstractStrategy已经持有algorithm这个接口,我们完全可以如下去写代码,让系统根据不同的实现执行不同的策略不就完了。代码可以如下:
Java代码
package com.icecode.demo; import com.icecode.demo.strategy.AbstractStrategy; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { AbstractStrategy strategy = new ConcreteStrategy1(); strategy.algorithm(); strategy = new ConcreteStrategy2(); strategy.algorithm(); } }
输出结果如下:
----------------我是策略一算法----------------
----------------我是策略二算法----------------
可见,2种方案都实现了同一个引用根据不同的实现执行特定的算法。是的,分析发现,在上面简单的应用中,Context的确可以取消。那么,Context这个角色为什么还要存在呢?
让我们考虑以下几种情况:
1、如果我们需要对不同策略中相同算法的参数,执行相同的安全性检查,我们如果没有环境角色Context,则只能在每个实现的开始部分,调用安全性检查代码;而有了Context这个角色,我们可以在调用Context的构造器时,统一进行安全性检查。这在我们的实现策略比较多的时候,比如说7、8个的时候,特别有用,可以大量减少冗余的代码量。
2、如果我们需要改变原有算法时,需要引进新的参数,如果没有Context,我们怎么办?一种办法是重载该算法,增加新的函数接口;另外一种办法是完全废弃原有的函数接口,重新写新的函数接口。毋庸置疑,这2种办法的代价都很大,尤其是如果这个新的参数只有部分实现策略中的该算法实现用到的时候。而我们使用Context就可以完全解决这个问题。
下面我们改造下上面那个基本策略模式,我们让策略模式也持有对Context的引用,这样的优点是可以在策略类里回调的Context里的所有可用的变量或函数等信息。此外,我们也增加一个新的实现策略类ConcreteStrategy3,具体代码如下所示:
Java代码
package com.icecode.demo.strategy; import com.icecode.demo.context.Context; /** * 抽象策略 * @author zhanche * */ public abstract class AbstractStrategy { /** * 某个希望有不同策略实现的算法 */ public abstract void algorithm(Context context); } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略二算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第三种具体实现策略 * @author zhanche * */ public class ConcreteStrategy3 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略三算法----------------"); } } package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { /** * 持有对策略的引用 */ private AbstractStrategy strategy; /** * 算法入口 */ public void algorithm() { this.strategy.algorithm(this); } }
好了,现在我们想这样改变需求,ConcreteStrategy2和ConcreteStrategy3里对algorithm算法的实现,需要统计两个新的信息,分别用parameter1和parameter2来表示,同时要统计所有实现策略类里,对algorithm算法调用的次数。
如果没有Context这个角色,又需要做到客户端调用的时候代码改动尽量少,相信大家的做法只好是改抽象策略类和实现策略类里的algorithm算法。但是这样实现策略ConcreteStrategy1可能不愿意了,因为他并不需要新增加的参数;此外,对所有实现类里algorithm算法调用的统计也没有一个统一的入口,需要在每个algorithm实现中,插入一个计数代码。但是如果有了环境角色Context,一切就变得很简单了,我们不需要改动抽象策略类,和实现策略类ConcreteStrategy1,只需要改需求发生变化相关的类,且看下面的代码:
Java代码
package com.icecode.demo.context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 环境角色,主要完成对特定策略的调用
* @author zhanche
*
*/
public class Context {
/**
* 持有对策略的引用
*/
private AbstractStrategy strategy;
/**
* parameter1、parameter2只是ConcreteStrategy2ConcreteStrategy3需要使用的参数,
* 而ConcreteStrategy1不使用
*/
private int parameter1;
private int parameter2;
//count用来统计所有策略的算法algorithm调用的总次数
public static int count = 0;
public Context(AbstractStrategy strategy) {
this.strategy = strategy;
}
public Context(AbstractStrategy strategy, int parameter1, int parameter2) {
super();
this.strategy = strategy;
this.parameter1 = parameter1;
this.parameter2 = parameter2;
}
public int getParameter1() {
return parameter1;
}
public int getParameter2() {
return parameter2;
}
/**
* 算法入口
*/
public void algorithm() {
count++;
System.out.println("------------这是第"+count+"次调用algorithm算法--------");
this.strategy.algorithm(this);
}
}
package com.icecode.demo.strategy.impl;
import com.icecode.demo.context.Context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 对算法的第一种具体实现策略
* @author zhanche
*
*/
public class ConcreteStrategy1 extends AbstractStrategy {
@Override
public void algorithm(Context context) {
System.out.println("----------------我是策略一算法----------------");
}
}
package com.icecode.demo.strategy.impl;
import com.icecode.demo.context.Context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 对算法的第二种具体实现策略
* @author zhanche
*
*/
public class ConcreteStrategy2 extends AbstractStrategy {
@Override
public void algorithm(Context context) {
System.out.println("----------------我是策略二算法----------------");
System.out.println("------------------我需要的参数parameter1="+context.getParameter1());
System.out.println("------------------我需要的参数parameter2="+context.getParameter2());
}
}
package com.icecode.demo.strategy.impl;
import com.icecode.demo.context.Context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 对算法的第三种具体实现策略
* @author zhanche
*
*/
public class ConcreteStrategy3 extends AbstractStrategy {
@Override
public void algorithm(Context context) {
System.out.println("----------------我是策略二算法----------------");
System.out.println("------------------我需要的参数parameter1="+context.getParameter1());
System.out.println("------------------我需要的参数parameter2="+context.getParameter2());
}
}
客户端测试的代码如下:
Java代码
package com.icecode.demo; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; import com.icecode.demo.strategy.impl.ConcreteStrategy3; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { Context context = new Context(new ConcreteStrategy1()); context.algorithm(); context = new Context(new ConcreteStrategy2(),100, 200); context.algorithm(); context = new Context(new ConcreteStrategy3(), 100, 200); context.algorithm(); } }
测试输出结果如下:
------------这是第1次调用algorithm算法--------
----------------我是策略一算法----------------
------------这是第2次调用algorithm算法--------
----------------我是策略二算法----------------
------------------我需要的参数parameter1=100
------------------我需要的参数parameter2=200
------------这是第3次调用algorithm算法--------
----------------我是策略三算法----------------
------------------我需要的参数parameter1=100
------------------我需要的参数parameter2=200
由以上分析可见,策略模式中,各个角色的功能都非常重要,虽然环境角色Context可以在某些简单的策略模式中不去使用,但是如果无法预测到各个实现策略功能和需求的变化,以及实现灵活性更好的策略模式,在使用策略模式进行架构时,一定要充分利用所有角色的功能。
java设计模式之——策略模式
设计模式Java算法java设计模式之——策略模式
1,什么是策略模式?
策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
2,策略模式有什么好处?
策略模式的好处在于你可以动态的改变对象的行为。
3,设计原则
设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。
策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响 到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
4 ,策略模式中有三个对象:
(1) 环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
(2) 抽象策略对象:它可由接口或抽象类来实现。
(3) 具体策略对象:它封装了实现同不功能的不同算法。
利用策略模式构建应用程序,可以根据用户配置等内容,选择不同有算法来实现应用程序的功能。具体的选择有环境对象来完成。采用这种方式可以避免由于使用条件语句而带来的代码混乱,提高应用程序的灵活性与条理性。
5,应用场景举例:
刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开能解决棘手问题,嘿,还别说,真解决了大问题,搞到最后是周瑜陪了夫人又折兵,那咱们先看看这个场景是什么样子的。
先说说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是亮哥给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜。用java程序怎么表现这些呢?
那我们先来看看图?
三个妙计是同一类型的东西,那咱就写个接口:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 首先定义一个策略接口,这是诸葛亮老人家给赵云的三个锦囊妙计的接口。 */ public interface IStrategy { //每个锦囊妙计都是一个可执行的算法。 public void operate(); }
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 首先定义一个策略接口,这是诸葛亮老人家给赵云的三个锦囊妙计的接口。 */ public interface IStrategy { //每个锦囊妙计都是一个可执行的算法。 public void operate(); }
然后再写三个实现类,有三个妙计嘛:
妙计一:初到吴国:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 找乔国老帮忙,使孙权不能杀刘备。 */ public class BackDoor implements IStrategy { @Override public void operate() { System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备..."); } }
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 找乔国老帮忙,使孙权不能杀刘备。 */ public class BackDoor implements IStrategy { @Override public void operate() { System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备..."); } }
妙计二:求吴国太开个绿灯,放行:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 求吴国太开个绿灯。 */ public class GivenGreenLight implements IStrategy { @Override public void operate() { System.out.println("求吴国太开个绿灯,放行!"); } }
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 求吴国太开个绿灯。 */ public class GivenGreenLight implements IStrategy { @Override public void operate() { System.out.println("求吴国太开个绿灯,放行!"); } }
妙计三:孙夫人断后,挡住追兵:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 孙夫人断后,挡住追兵。 */ public class BlackEnemy implements IStrategy { @Override public void operate() { System.out.println("孙夫人断后,挡住追兵..."); } }
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 孙夫人断后,挡住追兵。 */ public class BlackEnemy implements IStrategy { @Override public void operate() { System.out.println("孙夫人断后,挡住追兵..."); } }
好了,大家看看,三个妙计是有了,那需要有个地方放妙计啊,放锦囊里:
Java代码
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * */ public class Context { private IStrategy strategy; //构造函数,要你使用哪个妙计 public Context(IStrategy strategy){ this.strategy = strategy; } public void operate(){ this.strategy.operate(); } }
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * */ public class Context { private IStrategy strategy; //构造函数,要你使用哪个妙计 public Context(IStrategy strategy){ this.strategy = strategy; } public void operate(){ this.strategy.operate(); } }
然后就是赵云雄赳赳的揣着三个锦囊,拉着已步入老年行列,还想着娶纯情少女的,色咪咪的刘备老爷子去入赘了,嗨,还别说,亮哥的三个妙计还真不错,瞧瞧:
Java代码
package com.yangguangfu.strategy; public class ZhaoYun { /** * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 */ public static void main(String[] args) { Context context; //刚到吴国的时候拆开第一个 System.out.println("----------刚刚到吴国的时候拆开第一个---------------"); context = new Context(new BackDoor()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //当刘备乐不思蜀时,拆开第二个 System.out.println("----------刘备乐不思蜀,拆第二个了---------------"); context = new Context(new GivenGreenLight()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //孙权的小追兵了,咋办?拆开第三个锦囊 System.out.println("----------孙权的小追兵了,咋办?拆开第三个锦囊---------------"); context = new Context(new BlackEnemy()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); } }
package com.yangguangfu.strategy; public class ZhaoYun { /** * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 */ public static void main(String[] args) { Context context; //刚到吴国的时候拆开第一个 System.out.println("----------刚刚到吴国的时候拆开第一个---------------"); context = new Context(new BackDoor()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //当刘备乐不思蜀时,拆开第二个 System.out.println("----------刘备乐不思蜀,拆第二个了---------------"); context = new Context(new GivenGreenLight()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //孙权的小追兵了,咋办?拆开第三个锦囊 System.out.println("----------孙权的小追兵了,咋办?拆开第三个锦囊---------------"); context = new Context(new BlackEnemy()); context.operate();//拆开执行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); } }
后话:就这三招,搞得的周郎是“赔了夫人又折兵”呀!这就是策略模式,高内聚低耦合的特点也表现出来了,还有一个就是扩展性,也就是OCP原则,策略类可以继续添加下去气,只是修改Context.java就可以了,这个不多说了,自己领会吧。
http://zhanche2011.iteye.com/blog/1169948
Java策略模式(Strategy模式) 之体验
博客分类:Java程序
设计模式
Java 策略模式Java设计模式Java
Strategy模式环境角色Context 作用
本文探讨初学使用策略模式时遇到的一些疑惑,以及在工作中慢慢解决之前遇到的疑惑,借此与大家分享。比如说本文谈到策略模式中环境角色Context的用处,为什么一定要用,可不可以将此取消。这些都是在学习和工作的实践总结中慢慢体会到的。
首先,我们来看下策略模式的概念。一般的解释如下:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)
一般的,策略模式主要分为以下三个角色:
1. 环境角色(Context):持有一个策略类引用
2. 抽象策略(Strategy):定义了多个具体策略的公共接口,具体策略类中各种不同的算法以不同的方式实现这个接口;Context使用这些接口调用不同实现的算法。一般的,我们使用接口或抽象类实现。
3. 具体策略(ConcreteStrategy):实现抽象策略类中的相关的算法或操作。
我们首先来写一个简单的策略模式,然后再结合实际应用进行扩展,进而思考其在实际开发中的使用方法。
(给大家推荐前辈写的一篇不错的博文,研磨设计模式之 策略模式http://www.uml.org.cn/sjms/201009092.asp)
我们这个简单的策略假设就是想让不同的策略来实现某个算法(algorithm),抽象类如下:
Java代码
package com.icecode.demo.strategy; /** * 抽象策略 * @author zhanche * */ public abstract class AbstractStrategy { /** * 某个希望有不同策略实现的算法 */ public abstract void algorithm(); }
package com.icecode.demo.strategy; /** * 抽象策略 * @author zhanche * */ public abstract class AbstractStrategy { /** * 某个希望有不同策略实现的算法 */ public abstract void algorithm(); }
算法algorithm的具体实现策略类ConcreteStrategy1和ConcreteStrategy2如下:
Java代码
package com.icecode.demo.strategy.impl; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm() { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm() { System.out.println("----------------我是策略二算法----------------"); } }
package com.icecode.demo.strategy.impl; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm() { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm() { System.out.println("----------------我是策略二算法----------------"); } }
环境角色的实现如下:
Java代码
package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { private AbstractStrategy strategy; public Context(AbstractStrategy strategy) { this.strategy = strategy; } public void algorithm() { this.strategy.algorithm(); } }
package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { private AbstractStrategy strategy; public Context(AbstractStrategy strategy) { this.strategy = strategy; } public void algorithm() { this.strategy.algorithm(); } }
下面简单写一个客户端测试的代码:
Java代码
package com.icecode.demo; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { Context context = new Context(new ConcreteStrategy1()); context.algorithm(); context = new Context(new ConcreteStrategy2()); context.algorithm(); } }
package com.icecode.demo; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { Context context = new Context(new ConcreteStrategy1()); context.algorithm(); context = new Context(new ConcreteStrategy2()); context.algorithm(); } }
输出结果如下:
----------------我是策略一算法----------------
----------------我是策略二算法----------------
好吧,到此为止,一个简单的策略模式就写完了。但是,大家肯定有所疑惑,Context完全可以没有嘛,既然抽象策略AbstractStrategy已经持有algorithm这个接口,我们完全可以如下去写代码,让系统根据不同的实现执行不同的策略不就完了。代码可以如下:
Java代码
package com.icecode.demo; import com.icecode.demo.strategy.AbstractStrategy; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { AbstractStrategy strategy = new ConcreteStrategy1(); strategy.algorithm(); strategy = new ConcreteStrategy2(); strategy.algorithm(); } }
package com.icecode.demo; import com.icecode.demo.strategy.AbstractStrategy; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { AbstractStrategy strategy = new ConcreteStrategy1(); strategy.algorithm(); strategy = new ConcreteStrategy2(); strategy.algorithm(); } }
输出结果如下:
----------------我是策略一算法----------------
----------------我是策略二算法----------------
可见,2种方案都实现了同一个引用根据不同的实现执行特定的算法。是的,分析发现,在上面简单的应用中,Context的确可以取消。那么,Context这个角色为什么还要存在呢?
让我们考虑以下几种情况:
1、如果我们需要对不同策略中相同算法的参数,执行相同的安全性检查,我们如果没有环境角色Context,则只能在每个实现的开始部分,调用安全性检查代码;而有了Context这个角色,我们可以在调用Context的构造器时,统一进行安全性检查。这在我们的实现策略比较多的时候,比如说7、8个的时候,特别有用,可以大量减少冗余的代码量。
2、如果我们需要改变原有算法时,需要引进新的参数,如果没有Context,我们怎么办?一种办法是重载该算法,增加新的函数接口;另外一种办法是完全废弃原有的函数接口,重新写新的函数接口。毋庸置疑,这2种办法的代价都很大,尤其是如果这个新的参数只有部分实现策略中的该算法实现用到的时候。而我们使用Context就可以完全解决这个问题。
下面我们改造下上面那个基本策略模式,我们让策略模式也持有对Context的引用,这样的优点是可以在策略类里回调的Context里的所有可用的变量或函数等信息。此外,我们也增加一个新的实现策略类ConcreteStrategy3,具体代码如下所示:
Java代码
package com.icecode.demo.strategy; import com.icecode.demo.context.Context; /** * 抽象策略 * @author zhanche * */ public abstract class AbstractStrategy { /** * 某个希望有不同策略实现的算法 */ public abstract void algorithm(Context context); } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略二算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第三种具体实现策略 * @author zhanche * */ public class ConcreteStrategy3 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略三算法----------------"); } } package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { /** * 持有对策略的引用 */ private AbstractStrategy strategy; /** * 算法入口 */ public void algorithm() { this.strategy.algorithm(this); } }
package com.icecode.demo.strategy; import com.icecode.demo.context.Context; /** * 抽象策略 * @author zhanche * */ public abstract class AbstractStrategy { /** * 某个希望有不同策略实现的算法 */ public abstract void algorithm(Context context); } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略二算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第三种具体实现策略 * @author zhanche * */ public class ConcreteStrategy3 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略三算法----------------"); } } package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { /** * 持有对策略的引用 */ private AbstractStrategy strategy; /** * 算法入口 */ public void algorithm() { this.strategy.algorithm(this); } }
好了,现在我们想这样改变需求,ConcreteStrategy2和ConcreteStrategy3里对algorithm算法的实现,需要统计两个新的信息,分别用parameter1和parameter2来表示,同时要统计所有实现策略类里,对algorithm算法调用的次数。
如果没有Context这个角色,又需要做到客户端调用的时候代码改动尽量少,相信大家的做法只好是改抽象策略类和实现策略类里的algorithm算法。但是这样实现策略ConcreteStrategy1可能不愿意了,因为他并不需要新增加的参数;此外,对所有实现类里algorithm算法调用的统计也没有一个统一的入口,需要在每个algorithm实现中,插入一个计数代码。但是如果有了环境角色Context,一切就变得很简单了,我们不需要改动抽象策略类,和实现策略类ConcreteStrategy1,只需要改需求发生变化相关的类,且看下面的代码:
Java代码
package com.icecode.demo.context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 环境角色,主要完成对特定策略的调用
* @author zhanche
*
*/
public class Context {
/**
* 持有对策略的引用
*/
private AbstractStrategy strategy;
/**
* parameter1、parameter2只是ConcreteStrategy2ConcreteStrategy3需要使用的参数,
* 而ConcreteStrategy1不使用
*/
private int parameter1;
private int parameter2;
//count用来统计所有策略的算法algorithm调用的总次数
public static int count = 0;
public Context(AbstractStrategy strategy) {
this.strategy = strategy;
}
public Context(AbstractStrategy strategy, int parameter1, int parameter2) {
super();
this.strategy = strategy;
this.parameter1 = parameter1;
this.parameter2 = parameter2;
}
public int getParameter1() {
return parameter1;
}
public int getParameter2() {
return parameter2;
}
/**
* 算法入口
*/
public void algorithm() {
count++;
System.out.println("------------这是第"+count+"次调用algorithm算法--------");
this.strategy.algorithm(this);
}
}
package com.icecode.demo.strategy.impl;
import com.icecode.demo.context.Context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 对算法的第一种具体实现策略
* @author zhanche
*
*/
public class ConcreteStrategy1 extends AbstractStrategy {
@Override
public void algorithm(Context context) {
System.out.println("----------------我是策略一算法----------------");
}
}
package com.icecode.demo.strategy.impl;
import com.icecode.demo.context.Context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 对算法的第二种具体实现策略
* @author zhanche
*
*/
public class ConcreteStrategy2 extends AbstractStrategy {
@Override
public void algorithm(Context context) {
System.out.println("----------------我是策略二算法----------------");
System.out.println("------------------我需要的参数parameter1="+context.getParameter1());
System.out.println("------------------我需要的参数parameter2="+context.getParameter2());
}
}
package com.icecode.demo.strategy.impl;
import com.icecode.demo.context.Context;
import com.icecode.demo.strategy.AbstractStrategy;
/**
* 对算法的第三种具体实现策略
* @author zhanche
*
*/
public class ConcreteStrategy3 extends AbstractStrategy {
@Override
public void algorithm(Context context) {
System.out.println("----------------我是策略二算法----------------");
System.out.println("------------------我需要的参数parameter1="+context.getParameter1());
System.out.println("------------------我需要的参数parameter2="+context.getParameter2());
}
}
package com.icecode.demo.context; import com.icecode.demo.strategy.AbstractStrategy; /** * 环境角色,主要完成对特定策略的调用 * @author zhanche * */ public class Context { /** * 持有对策略的引用 */ private AbstractStrategy strategy; /** * parameter1、parameter2只是ConcreteStrategy2ConcreteStrategy3需要使用的参数, * 而ConcreteStrategy1不使用 */ private int parameter1; private int parameter2; //count用来统计所有策略的算法algorithm调用的总次数 public static int count = 0; public Context(AbstractStrategy strategy) { this.strategy = strategy; } public Context(AbstractStrategy strategy, int parameter1, int parameter2) { super(); this.strategy = strategy; this.parameter1 = parameter1; this.parameter2 = parameter2; } public int getParameter1() { return parameter1; } public int getParameter2() { return parameter2; } /** * 算法入口 */ public void algorithm() { count++; System.out.println("------------这是第"+count+"次调用algorithm算法--------"); this.strategy.algorithm(this); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第一种具体实现策略 * @author zhanche * */ public class ConcreteStrategy1 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略一算法----------------"); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第二种具体实现策略 * @author zhanche * */ public class ConcreteStrategy2 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略二算法----------------"); System.out.println("------------------我需要的参数parameter1="+context.getParameter1()); System.out.println("------------------我需要的参数parameter2="+context.getParameter2()); } } package com.icecode.demo.strategy.impl; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.AbstractStrategy; /** * 对算法的第三种具体实现策略 * @author zhanche * */ public class ConcreteStrategy3 extends AbstractStrategy { @Override public void algorithm(Context context) { System.out.println("----------------我是策略二算法----------------"); System.out.println("------------------我需要的参数parameter1="+context.getParameter1()); System.out.println("------------------我需要的参数parameter2="+context.getParameter2()); } }
客户端测试的代码如下:
Java代码
package com.icecode.demo; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; import com.icecode.demo.strategy.impl.ConcreteStrategy3; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { Context context = new Context(new ConcreteStrategy1()); context.algorithm(); context = new Context(new ConcreteStrategy2(),100, 200); context.algorithm(); context = new Context(new ConcreteStrategy3(), 100, 200); context.algorithm(); } }
package com.icecode.demo; import com.icecode.demo.context.Context; import com.icecode.demo.strategy.impl.ConcreteStrategy1; import com.icecode.demo.strategy.impl.ConcreteStrategy2; import com.icecode.demo.strategy.impl.ConcreteStrategy3; /** * 策略模式测试类 * @author zhanche * */ public class Client { /** * @param args */ public static void main(String[] args) { Context context = new Context(new ConcreteStrategy1()); context.algorithm(); context = new Context(new ConcreteStrategy2(),100, 200); context.algorithm(); context = new Context(new ConcreteStrategy3(), 100, 200); context.algorithm(); } }
测试输出结果如下:
------------这是第1次调用algorithm算法--------
----------------我是策略一算法----------------
------------这是第2次调用algorithm算法--------
----------------我是策略二算法----------------
------------------我需要的参数parameter1=100
------------------我需要的参数parameter2=200
------------这是第3次调用algorithm算法--------
----------------我是策略三算法----------------
------------------我需要的参数parameter1=100
------------------我需要的参数parameter2=200
由以上分析可见,策略模式中,各个角色的功能都非常重要,虽然环境角色Context可以在某些简单的策略模式中不去使用,但是如果无法预测到各个实现策略功能和需求的变化,以及实现灵活性更好的策略模式,在使用策略模式进行架构时,一定要充分利用所有角色的功能。
相关文章推荐
- 关于java中调用Rserve包的eval函数中的奇葩bug
- Java继承和接口
- Java制作证书的工具keytool用法总结
- java nio的一个严重BUG(转)
- java输出调试技巧及Eclipse快捷键使用方法
- Java序列化的几种方式以及序列化的作用
- java标准标签库JSTL详解
- Java和MySQL数据库的连接
- java的动态代理机制详解
- Java下获取可用CPU数
- Java对象的创建及访问
- java观察者模式(转)
- java回调机制及其实现(转)
- 关于java中static关键字的读书笔记
- spring 生命周期
- mysql/Java服务端对emoji的支持
- java基础总结
- 接口和抽象类的区别
- Spring中Singleton模式的线程安全
- (转)Spring中Singleton模式的线程安全