算法策略的主动选择, 拒绝 if...else...(策略模式 + 简单工厂模式)
作者:小鑫同学
- 2022-10-13 北京
本文字数:3480 字
阅读完需:约 11 分钟
大家好,我是小鑫同学。一位从事过 Android 开发、混合开发,现在长期从事前端开发的编程爱好者,我觉得在编程之路上最重要的是知识的分享,所谓三人行必有我师。所以我开始在社区持续输出我所了解到、学习到、工作中遇到的各种编程知识,欢迎有想法、有同感的伙伴加我fe-xiaoxin微信交流~
算法策略的主动选择,拒绝 if...else...(策略模式+简单工厂模式)
本文通过一个切换加解密算法的 Demo 来学习如何使代码的调用和封装都变的更加简单
1. 抽象策略接口
/**
* 加密算法接口:封装算法的公共操作加密和解密
*
* @author Spoon
* @version 1.0.0
*/
public interface SecurityStrategy {
/**
* 加密
*/
public String doEncryption(String key, String plaintext);
/**
* 解密
*/
public String doDeciphering(String key, String ciphertext);
}
复制代码
2. 策略算法的具体实现
/**
* AES加密算法具体实现类
*
* @author Spoon
* @version 1.0.0
*/
public class AesStrategy implements SecurityStrategy{
@Override
public String doEncryption(String key, String plaintext) {
String dec = "";
try {
dec = AESUtil.encrypt(plaintext, key, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return dec;
}
@Override
public String doDeciphering(String key, String ciphertext) {
String enc = "";
try {
enc = AESUtil.decrypt(ciphertext, key);
} catch (Exception e) {
e.printStackTrace();
}
return enc;
}
}
复制代码
/**
* DES3加密算法具体实现类
*
* @author Spoon
* @version 1.0.0
*/
public class Des3Strategy implements SecurityStrategy{
@Override
public String doEncryption(String key, String plaintext) {
String dec = "";
try {
dec = ThreeDES.encode(plaintext, key);
} catch (Exception e) {
e.printStackTrace();
}
return dec;
}
@Override
public String doDeciphering(String key, String ciphertext) {
String enc = "";
try {
enc = ThreeDES.decode(ciphertext, key);
} catch (Exception e) {
e.printStackTrace();
}
return enc;
}
}
复制代码
3. 加密算法类型枚举
/**
* 加密算法类型枚举
* @author Spoon
* @version 1.0.0
*/
public enum StrategyType {
AES(1,"AES加密算法"),
DES3(2,"DES3加密算法");
private int index;
private String desc;
private StrategyType(int index, String desc){
this.index = index;
this.desc = desc;
}
public int index() {
return index;
}
public String desc() {
return desc;
}
}
复制代码
4. 使用简单工厂获取具体实现
/**
* 策略工厂类:将每个实现策略注册到工厂,并根据Type返回指定策略实现
* @author Spoon
* @version 1.0.0
*/
public class StrategyFactory {
private static Map<Integer, SecurityStrategy> services = new ConcurrentHashMap<Integer, SecurityStrategy>();
static {
services.put(StrategyType.AES.index(), new AesStrategy());
services.put(StrategyType.DES3.index(), new Des3Strategy());
}
private StrategyFactory() {
}
public static SecurityStrategy getSecurity(Integer type) {
return services.get(type);
}
}
复制代码
5. 策略上下文完成工厂返回实现的具体调用
/**
* 策略上下文:实际操作对象,接收传入的Type和必要参数,内部调用策略工厂类获取实际实现类进行加解密操作
*
* @author Spoon
* @version 1.0.0
*/
public class StrategyContext {
private SecurityStrategy strategy;
public StrategyContext() {
}
public SecurityStrategy getStrategy() {
return strategy;
}
public void setStrategy(SecurityStrategy strategy) {
this.strategy = strategy;
}
public String executeEncryptionStrategy(Integer type, String key, String plaintext) {
strategy = StrategyFactory.getSecurity(type);
return strategy.doEncryption(key, plaintext);
}
public String executeDecipheringStrategy(Integer type, String key, String ciphertext) {
strategy = StrategyFactory.getSecurity(type);
return strategy.doDeciphering(key, ciphertext);
}
}
复制代码
6. Test
/**
* 测试类
* String key_aes = "789tenc963qAzWsX";
* String key_des3 = "1234567890ASDFGH12345678";
*/
public class Main {
@SuppressWarnings("resource")
public static void main(String[] args) {
String plaintext = "ABCDEFGHIJKLMNOPQRST";
System.out.println("请选择加密算法(AES:1, DES3:2) :");
int type = new Scanner(System.in).nextInt();
System.out.println("请输入加密秘钥 :");
String key = new Scanner(System.in).nextLine();
StrategyContext context = new StrategyContext();
System.out.println(context.executeEncryptionStrategy(type, key, plaintext));
}
}
复制代码
通过测试 Main 方法可以看出,在增加加密算法后对调用方来说只需要关注加密算法的 Type 值就可以,调用形式也没有发生改变,没有使用条件语句进行判断,减少了调用时出错的风险,对于提供方来说,主要关注点就是策略算法的具体实现,并添加相应的枚举后将实现的策略注册到策略工厂中即可。
Python 版本 :
from abc import ABCMeta,abstractmethod
class SecurityStrategy:
__metaclass__ = ABCMeta # 指定这是一个抽象类
@abstractmethod # 抽象方法
def doEncryption(self, key, plaintext):
pass
@abstractmethod # 抽象方法
def doDeciphering(self, key, ciphertext):
pass
复制代码
from SecurityStrategy import SecurityStrategy
class AesStrategy(SecurityStrategy):
def doEncryption(self, key, plaintext):
print('AES === > ', 'key : ', key, 'plaintext : ', plaintext)
def doDeciphering(self, key, ciphertext):
print('AES === > ', 'key : ', key, 'ciphertext : ', ciphertext)
复制代码
from SecurityStrategy import SecurityStrategy
class Des3Strategy(SecurityStrategy):
def doEncryption(self, key, plaintext):
print('Des3 === > ', 'key : ', key, 'plaintext : ', plaintext)
def doDeciphering(self, key, ciphertext):
print('Des3 === > ', 'key : ', key, 'ciphertext : ', ciphertext)
复制代码
from enum import Enum
class StrategyType(Enum):
AES = 1
DES3 = 2
复制代码
from StrategyType import StrategyType
from impl.AesStrategy import AesStrategy
from impl.Des3Strategy import Des3Strategy
class StrategyFactory:
services = {
StrategyType.AES.value: AesStrategy(),
StrategyType.DES3.value: Des3Strategy()
}
@staticmethod
def getSecurity(type):
return StrategyFactory.services[type]
复制代码
from StrategyFactory import StrategyFactory
class StrategyContext:
@staticmethod
def executeEncryptionStrategy(type, key, plaintext):
return StrategyFactory.getSecurity(type).doEncryption(key, plaintext)
@staticmethod
def executeDecipheringStrategy(type, key, ciphertext):
return StrategyFactory.getSecurity(type).doDeciphering(key, ciphertext)
复制代码
from StrategyContext import StrategyContext
if __name__ == '__main__':
print("---------------开始测试-------------------")
StrategyContext.executeEncryptionStrategy(1, '1234567890ASDFGH12345678', 'ABCDEFGHIJKLMNOPQRST')
StrategyContext.executeDecipheringStrategy(1, '1234567890ASDFGH12345678', 'ABCDEFGHIJKLMNOPQRST')
StrategyContext.executeEncryptionStrategy(2, '1234567890ASDFGH12345678', 'ABCDEFGHIJKLMNOPQRST')
StrategyContext.executeDecipheringStrategy(2, '1234567890ASDFGH12345678', 'ABCDEFGHIJKLMNOPQRST')
print("---------------结束测试-------------------")
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 5
版权声明: 本文为 InfoQ 作者【小鑫同学】的原创文章。
原文链接:【http://xie.infoq.cn/article/24eccc3b8bb4e34359986bfdb】。文章转载请联系作者。
小鑫同学
关注
⚡InfoQ签约作者 2018-12-10 加入
还未添加个人简介
评论