Java设计模式--策略模式【Strategy Pattern】

本文详细介绍了Java中的策略模式,这是一种行为设计模式,用于封装一系列算法并使它们可以互换。通过策略模式,算法的使用与算法本身分离,增强了系统的可维护性和可扩展性。文中通过排序算法的实例展示了如何实现策略模式,探讨了其优点如避免多重条件语句,以及缺点如客户端需了解所有策略类。

       策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化

   策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。

   通用UML如下:

   

这个模式涉及到三个角色:

  环境(Context)角色:持有一个Strategy的引用。

  抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

  具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

  下面以排序算法为例,利用策略模式,简要实现冒泡排序和选择排序算法。

  首先定义抽象策略角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

  代码如下:

package com.pattern.strategy;
/**
 * 策略模式的抽象策略角色:这里主要是定义抽象的排序算法
 * @author
 *
 */
public interface SortStrategy {
   public void sort(int[] arr);//定义抽象排序算法
}
其次定义排序的具体类,具体类包装了相关的算法或行为。

冒泡排序代码如下:

package com.pattern.strategy;
/**
 * 冒泡排序算法:从数组下标为0的位置开始,比较下标位置为0和1的数据,如果0号位置的大,则交换位置,如果1号位置大,则什么也不做,
 * 然后右移一个位置,比较1号和2号的数据,和刚才的一样,如果1号的大,则交换位置,以此类推直至最后一个位置结束,
 * 到此数组中最大的元素就被排到了最后,之后再根据之前的步骤开始排前面的数据,直至全部数据都排序完成
 * @author 
 *
 */
public class BubbleSort implements SortStrategy {
	@Override
	public void sort(int[] arr) {
		for(int i=0;i<arr.length;i++){
			for(int j=0;j<arr.length-1;j++){
				if(arr[j]>arr[j+1]){//相邻的两个数,如果前面的数大,则交换位置
					int arrtemp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=arrtemp;
				}
			}
		}

	}

}
选择排序代码如下:

package com.pattern.strategy;
/**
 * 选择排序算法:在选择排序中,不再只比较两个相邻的数据。
 * 因此需要记录下某一个数据的下标,进行选择排序就是把所有的数据扫描一遍,从中挑出(按从小到大排序)最小的一个数据,
 * 这个最小的数据和最左端下标为0的数据交换位置。之后再次扫描数据,从下标为1开始,还是挑出最小的然后和1号位置进行交换,这个过程一直持续到所有的数据都排定。
 * 而程序中需要有一个标识变量来标识每次挑出最小数据的下标
 * @author 
 *
 */
public class SelectSort implements SortStrategy {

	public void sort(int[] arr) {
		for(int i=0;i<arr.length;i++){
			int index=i;
			for(int j=i+1;j<arr.length;j++){
				if(arr[index]>arr[j]){//记录相对较小的数值的下标
					index=j;
				}
			}
			int t=arr[index];//交换最小的数值位置,直到最前面
			arr[index]=arr[i];
			arr[i]=t;
		}
	}
}

环境角色:

package com.pattern.strategy;
/**
 * 策略模式环境上下文角色
 * @author 
 *
 */
public class SortContext {
   private SortStrategy strategy;//持有一个具体的策略对象

public SortContext(SortStrategy strategy) {
	super();
	this.strategy = strategy;
}

public void sort(int[] arr){
	this.strategy.sort(arr);
} 
}

客户端类:

package com.pattern.strategy;
/**
 * 客户端测试
 * @author 
 *
 */
public class Client {

	public static void main(String[] args) {
		int[] arr={23,2,56,1,78,9,11,98,10,45};
		SortStrategy s=new BubbleSort();
		SortContext context=new SortContext(s);
		context.sort(arr);
		System.out.println("冒泡排序结果:");
		for(int i=0;i<arr.length;i++){
			System.out.print(arr[i]+"  ");
		}
		int[] arr2={23,2,56,1,78,9,11,98,10,45};
		SortStrategy s2=new SelectSort();
		SortContext context2=new SortContext(s2);
		context2.sort(arr2);
		System.out.println("");
		System.out.println("选择排序结果:");
		for(int i=0;i<arr2.length;i++){
			System.out.print(arr2[i]+"  ");
		}
	}
}

输出结果:


      从上面的示例可以看出,策略模式仅仅封装算法,提供新的算法插入到已有系统中,以及老算法从系统中“退休”的方法,策略模式并不决定在何时使用何种算法。在什么情况下使用什么算法是由客户端决定的。

  策略模式有以下特点:

  1、策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。

  2、策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。

  3、运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。

  4、若所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。

策略模式的优点

  (1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。

  (2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

策略模式的缺点

  (1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。

  (2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。


参考博文:http://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html


源码下载:http://download.youkuaiyun.com/download/pelifymeng2/9994744


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值