您的位置:首页 > 其它

策略模式(一)

2014-06-06 22:31 106 查看
策略模式:定义一系列算法,把它们一个个封装起来,并且使他们可以相互替换.

在某些设计中,一些类的设计人员经常遇到这样的问题:由于用户需求的变化,导致经常需要修改类中的某个方法,即需要不断的改变算法.

面对这样的问题,不用担心,面向对象编程有一个很好的设计原则"面向抽象编程",该原则的核心就是将类中经常需要变化的部分分割出来,

并且把每种可能的变化对应的交给抽象类的一个子类去负责,从而让类的设计者不用去关心具体实现.

策略模式结构中包括三个角色:

策略:策略是一个接口,该接口定义了若干个算法标识,即定义了若干个抽象方法.

具体策略:具体策略是实现策略接口的类,具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体算法.

上下文:上下文是依赖于策略接口的类,即上下文中包含策略声明的变量,并且为此变量提供了set方法,最后还提供了一个方法用来委托策略变量

调用具体策略的方法.

应用场景一:在某个比赛中,有若干个评委为选手评分,请给出几种策略根据评委的评分为选手计算一个最后结果.

1.策略接口类,直接看代码:StrategyInterface.

<span style="font-size:12px;">package com.ilucky.pattern.strategy.one;

/**
 * @author IluckySi
 * @date 20140604
 */
public interface StrategyInterface {

	public abstract double computeScore(double[] scores);
}</span>


2.具体策略类,直接看代码StrategyOne,StrategyTwo,StrategyThree.

<span style="font-size:12px;"> * @author IluckySi
 * @date 20140604
 */
//计算代数平均值.
public class StrategyOne implements StrategyInterface {

	@Override
	public double computeScore(double[] scores) {
		double average = 0.0;
		double sum = 0.0;
		for(int i = 0; scores != null && i < scores.length; i++) {
			sum += scores[i];
		}
		average = sum / scores.length;
		return average;
	}
}</span>
<span style="font-size:12px;">package com.ilucky.pattern.strategy.one;

import java.util.Arrays;

/**
 * @author IluckySi
 * @date 20140604
 */
//计算几何平均值.
public class StrategyTwo implements StrategyInterface {

	@Override
	public double computeScore(double[] scores) {
		double average = 0.0;
		double sum = 1.0;
		Arrays.sort(scores);
		for(int i = 0; i < scores.length; i++) {
			sum *= scores[i];
		}
		average = Math.pow(sum, 1.0 / scores.length);
		return average;
	}
}
</span>
<span style="font-size:12px;">package com.ilucky.pattern.strategy.one;

import java.util.Arrays;

/**
 * @author IluckySi
 * @date 20140604
 */
//计算去掉一个最高分和最低分代数平均值.
public class StrategyThree implements StrategyInterface {

	@Override
	public double computeScore(double[] scores) {
		double average = 0.0;
		double sum = 0.0;
		Arrays.sort(scores);
		for(int i = 1; i < scores.length - 1; i++) {
			sum += scores[i];
		}
		average = sum / (scores.length - 2);
		return average;
	}
}</span>


3.上下文类,直接看代码Context.

<span style="font-size:12px;">package com.ilucky.pattern.strategy.one;

/**
 * @author IluckySi
 * @date 20140604
 */
public class Context {

	private StrategyInterface strategyInterface;

	public void setStrategyInterface(StrategyInterface strategyInterface) {
		this.strategyInterface = strategyInterface;
	}
	
	public double computeScore(double[] scores) {
		return strategyInterface.computeScore(scores);
	}
}</span>


4.最后看测试类MainTest。

<span style="font-size:12px;">package com.ilucky.pattern.strategy.one;

/**
 * @author IluckySi
 * @date 20140604
 */
public class MainTest {

	public static void main(String[] args) {
		
		//模拟评分.
		double[] scores = new double[6];
		scores[0] = 50;
		scores[1] = 68;
		scores[2] = 72;
		scores[3] = 85;
		scores[4] = 90;
		scores[5] = 96;
		
		//创建上下文.
		Context context = new Context();
		
		//计算代数平均值.
		StrategyInterface strategyOne = new StrategyOne();
		context.setStrategyInterface(strategyOne);
		double resultOne = context.computeScore(scores);
		System.out.println("代数平均值:" + resultOne);
		
		//计算几何平均值.
		StrategyInterface strategyTwo = new StrategyTwo();
		context.setStrategyInterface(strategyTwo);
		double resultTwo = context.computeScore(scores);
		System.out.println("几何平均值:" + resultTwo);
				
		//计算去掉一个最高分和最低分代数平均值.
		StrategyInterface strategyThredd = new StrategyThree();
		context.setStrategyInterface(strategyThredd);
		double resultThreee = context.computeScore(scores);
		System.out.println("去掉一个最高分和最低分代数平均值:" + resultThreee);
	}
}
/**
 运行结果:
 代数平均值:76.83333333333333
几何平均值:75.12607167549113
去掉一个最高分和最低分代数平均值:78.75
*/</span>


应用场景二:在某个数据传输业务中,需要为文件提供几种策略用来为文件加密解密.

1.策略接口类,直接看代码:StrategyInterface.

<span style="font-size:12px;">package com.ilucky.pattern.strategy.two;

import java.io.File;

/**
 * @author IluckySi
 * @date 20140605
 */
public interface StrategyInterface {

	public abstract void encrypt(File file);
	
	public abstract void decrypt(File file);
}</span>


2.具体策略类,直接看代码StrategyOne,StrategyTwo.

<span style="font-size:12px;">package com.ilucky.pattern.strategy.two;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * @author IluckySi
 * @date 20140605
 */
public class StrategyOne implements StrategyInterface {

	private String password;
	
	public StrategyOne() {
		this.password = "IluckySi";
	}
	
	public StrategyOne(String password) {
		this.password = password;
	}
	
	/**
	 * 使用一个字符串做密码,比如用IluckySi做密码,首先将IluckySi转换为一个字节数组,然后获取bytes数组的长度length,
	 * 最后将文件的内容按顺序以length个字节为一组,对每一组中的字节和bytes字节数组中对应的字节做加法运算.
	 */
	@Override
	public void encrypt(File file) {
		byte[] passwordBytes = password.getBytes();
		FileInputStream fis = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		try {
			//对文件内容加密.
			fis = new FileInputStream(file);
			bis = new BufferedInputStream(fis);
			long fileLength = file.length();
			byte[] bytes = new byte[(int)fileLength];
			//重点:将文件流内容转换为byte数组.
			int bytesLength = bis.read(bytes);
			for(int i = 0; i < bytesLength; i++) {
				int encrpyt = bytes[i] + passwordBytes[i % passwordBytes.length];
				bytes[i] = (byte)encrpyt;
			}
			//对文件内容加完密再写回文件.
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			fos.write(bytes, 0 , bytesLength);
			System.out.println("文件" + file.getPath() + "已经成功完成加密!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(bos != null) {
					bos.close();
					bos = null;
				}
				if(fos != null) {
					fos.close();
					fos = null;
				}
				if(bis != null) {
					bis.close();
					bis = null;
				}
				if(fis != null) {
					fis.close();
					fis = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 将文件按密码的长度分组, 然后和密码对应的字节数组做减法运算.
	 */
	@Override
	public void decrypt(File file) {
		byte[] passwordBytes = password.getBytes();
		FileInputStream fis = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		try {
			//对文件内容解密.
			fis = new FileInputStream(file);
			bis = new BufferedInputStream(fis);
			long fileLength = file.length();
			byte[] bytes = new byte[(int)fileLength];
			//重点:将文件流内容转换为byte数组.
			int bytesLength = bis.read(bytes);
			for(int i = 0; i < bytesLength; i++) {
				int encrpyt = bytes[i] - passwordBytes[i % passwordBytes.length];
				bytes[i] = (byte)encrpyt;
			}
			//对文件内容解完密再写回文件.
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			fos.write(bytes);
			System.out.println("文件" + file.getPath() + "已经成功完成解密!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(bos != null) {
					bos.close();
					bos = null;
				}
				if(fos != null) {
					fos.close();
					fos = null;
				}
				if(bis != null) {
					bis.close();
					bis = null;
				}
				if(fis != null) {
					fis.close();
					fis = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
</span>
<span style="font-size:12px;">package com.ilucky.pattern.strategy.two;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * @author IluckySi
 * @date 20140606
 */
public class StrategyTwo implements StrategyInterface {

private String password;
	
	public StrategyTwo() {
		this.password = "IluckySi";
	}
	
	public StrategyTwo(String password) {
		this.password = password;
	}
	
	/**
	 * 使用一个字符串做密码,比如用IluckySi做密码,首先将IluckySi转换为一个字节数组,然后获取bytes数组的长度length,
	 * 最后将文件的内容按顺序以length个字节为一组,对每一组中的字节和bytes字节数组中对应的字节做异或运算.
	 */
	@Override
	public void encrypt(File file) {
		byte[] passwordBytes = password.getBytes();
		FileInputStream fis = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		try {
			//对文件内容加密.
			fis = new FileInputStream(file);
			bis = new BufferedInputStream(fis);
			long fileLength = file.length();
			byte[] bytes = new byte[(int)fileLength];
			//重点:将文件流内容转换为byte数组.
			int bytesLength = bis.read(bytes);
			for(int i = 0; i < bytesLength; i++) {
				int encrpyt = bytes[i] ^ passwordBytes[i % passwordBytes.length];
				bytes[i] = (byte)encrpyt;
			}
			//对文件内容加完密再写回文件.
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			fos.write(bytes, 0 , bytesLength);
			System.out.println("文件" + file.getPath() + "已经成功完成加密!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(bos != null) {
					bos.close();
					bos = null;
				}
				if(fos != null) {
					fos.close();
					fos = null;
				}
				if(bis != null) {
					bis.close();
					bis = null;
				}
				if(fis != null) {
					fis.close();
					fis = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 将文件按密码的长度分组, 然后和密码对应的字节数组做异或运算.
	 */
	@Override
	public void decrypt(File file) {
		byte[] passwordBytes = password.getBytes();
		FileInputStream fis = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		try {
			//对文件内容解密.
			fis = new FileInputStream(file);
			bis = new BufferedInputStream(fis);
			long fileLength = file.length();
			byte[] bytes = new byte[(int)fileLength];
			//重点:将文件流内容转换为byte数组.
			int bytesLength = bis.read(bytes);
			for(int i = 0; i < bytesLength; i++) {
				int encrpyt = bytes[i] ^ passwordBytes[i % passwordBytes.length];
				bytes[i] = (byte)encrpyt;
			}
			//对文件内容解完密再写回文件.
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			fos.write(bytes);
			System.out.println("文件" + file.getPath() + "已经成功完成解密!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(bos != null) {
					bos.close();
					bos = null;
				}
				if(fos != null) {
					fos.close();
					fos = null;
				}
				if(bis != null) {
					bis.close();
					bis = null;
				}
				if(fis != null) {
					fis.close();
					fis = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}</span>


重点:将文件流内容转换为byte数组.:byte[] bytes = new byte[(int)fileLength],int bytesLength = bis.read(bytes)。

3.上下文类,直接看代码Context.

<span style="font-size:12px;">package com.ilucky.pattern.strategy.two;

import java.io.File;

/**
 * @author IluckySi
 * @date 20140605
 */
public class Context {

	private StrategyInterface strategyInterface;

	public void setStrategyInterface(StrategyInterface strategyInterface) {
		this.strategyInterface = strategyInterface;
	}
	
	public void encrypt(File file) {
		strategyInterface.encrypt(file);
	}

	public void decrypt(File file) {
		strategyInterface.decrypt(file);
	}
}</span>


4.最后看测试类MainTest.

<span style="font-size:12px;">package com.ilucky.pattern.strategy.two;

import java.io.File;

/**
 * @author IluckySi
 * @date 20140605
 */
public class MainTest {

	public static void main(String[] args) {
		
		//测试文件.
		File one = new File("E:/one.txt");
		File two = new File("E:/two.txt");
		
		//创建上下文.
		Context context = new Context();
		
		//通过第一种策略加密解密.
		StrategyInterface strategyOne = new StrategyOne();
		context.setStrategyInterface(strategyOne);
		context.encrypt(one);
		context.decrypt(one);
		
		//通过第二种策略加密解密.
		StrategyInterface strategyTwo = new StrategyTwo();
		context.setStrategyInterface(strategyTwo);
		context.encrypt(two);
		context.decrypt(two);
	}
}
</span>
策略模式的优点:上下文和具体策略是松耦合关系,即上下文中包含一个策略变量,但不需要知道具体的策略是什么.

另外策略模式满足"开闭原则",即当增加新的具体策略时,不需要修改上下文类的的代码就可以引用具体策略的实例.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: