《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()); } }