《Head First Design Patterns》策略模式学习练习:
没有采用书中给出的demo,以我们常见的“字符串加密解密”实体类为例。
选择理由:加密解密方式有很多种,像MD5加密,AES加密。而这些在后期可能会因为种种需求而进行调整或者切换。采用策略模式,可以使这些变化变得可控,而不会影响之前的代码。(具体代码附在最后)
大概设计: 接口Processor,接口具体实现AESProcessor和DESProfessor分别实现了AES加密和DES加密。 PassWord需要进行加密,则注入Processor可通过setProcessor方法改变加密方式。
设计原则:
1.把需要变化的地方取出并封装
2.多用组合,少用继承
3.针对接口编程,不针对实现编程
/*
*处理方式接口
*/
public interface Processor {
/*
* 加密
*/
public String encrypt(String data,String key) throws Exception;
/*
* 解密
*/
public String decrypt(String pass,String key) throws Exception;
}
/*
* AES处理方式
*/
public class AESProcessor implements Processor{
/**
* AES加密为base 64 code
* @param content 待加密的内容
* @param encryptKey 加密密钥
* @return 加密后的base 64 code
* @throws Exception
*/
public String encrypt(String content, String encryptKey){
try{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(encryptKey.getBytes()));
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
return base64Encode(cipher.doFinal(content.getBytes("utf-8")));
}catch(Exception e){
return "";
}
}
/**
* 将base 64 code AES解密
* @param encryptStr 待解密的base 64 code
* @param decryptKey 解密密钥
* @return 解密后的string
* @throws Exception
*/
public String decrypt(String encryptStr, String decryptKey){
String result = "";
try {
if(!(encryptStr==null || "".equals(encryptStr))){
byte[] encryptBytes = base64Decode(encryptStr);
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(decryptKey.getBytes()));
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
result = new String(decryptBytes);
}
} catch (Exception e) {
// TODO Auto-generated catch block
result = "";
}
return result;
}
/**
* base 64 encode
* @param bytes 待编码的byte[]
* @return 编码后的base 64 code
*/
public static String base64Encode(byte[] bytes){
return new BASE64Encoder().encode(bytes);
}
/**
* base 64 decode
* @param base64Code 待解码的base 64 code
* @return 解码后的byte[]
* @throws Exception
*/
public static byte[] base64Decode(String base64Code) throws Exception{
return base64Code==null || "".equals(base64Code)? null : new BASE64Decoder().decodeBuffer(base64Code);
}
}
/*
* DES处理方式
*/
public class DESProcessor implements Processor{
//算法名称
public static final String KEY_ALGORITHM = "DES";
//算法名称/加密模式/填充方式
//DES共有四种工作模式-->>ECB:电子密码本模式、CBC:加密分组链接模式、CFB:加密反馈模式、OFB:输出反馈模式
public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
/**
* 加密数据
* @param data 待加密数据
* @param key 密钥
* @return 加密后的数据
*/
public String encrypt(String data, String key) throws Exception {
Key deskey = keyGenerator(key);
// 实例化Cipher对象,它用于完成实际的加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecureRandom random = new SecureRandom();
// 初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
byte[] results = cipher.doFinal(data.getBytes());
// 该部分是为了与加解密在线测试网站(http://tripledes.online-domain-tools.com/)的十六进制结果进行核对
for (int i = 0; i < results.length; i++) {
System.out.print(results[i] + " ");
}
System.out.println();
// 执行加密操作。加密后的结果通常都会用Base64编码进行传输
return Base64.encodeBase64String(results);
}
/**
* 解密数据
* @param data 待解密数据
* @param key 密钥
* @return 解密后的数据
*/
public String decrypt(String data, String key) throws Exception {
Key deskey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, deskey);
// 执行解密操作
return new String(cipher.doFinal(Base64.decodeBase64(data)));
}
private SecretKey keyGenerator(String keyStr) throws Exception {
byte input[] = HexString2Bytes(keyStr);
DESKeySpec desKey = new DESKeySpec(input);
//创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
return securekey;
}
private static int parse(char c) {
if (c >= 'a') return (c - 'a' + 10) & 0x0f;
if (c >= 'A') return (c - 'A' + 10) & 0x0f;
return (c - '0') & 0x0f;
}
// 从十六进制字符串到字节数组转换
public static byte[] HexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
}
//password类
public class PassWord {
protected String data;
protected String key;
protected Processor processor;
public PassWord(String data,String key){
this.data = data;
this.key = key;
}
/*
* 加密
*/
public String encrypt() throws Exception{
return this.processor.encrypt(this.data, this.key);
}
/*
* 解密
*/
public String decode() throws Exception{
return this.processor.decrypt(this.data,this.key);
}
public Processor getProcessor() {
return processor;
}
public void setProcessor(Processor processor) {
this.processor = processor;
}
}
//测试
public class Test {
public static void main(String[] args) throws Exception{
String key ="9588028820109132570743325311898426347857298773549468758875018579537757772163084478873699447306034466200616411960574122434059469100235892702736860872901247123456";
PassWord pass = new PassWord("123",key);
pass.setProcessor(new AESProcessor());
System.out.println(pass.encrypt());
pass.setProcessor(new DESProcessor());
System.out.println(pass.encrypt());
}
}