算法策略的主动选择,拒绝if...else...(策略模式+简单工厂模式)

算法策略的主动选择,拒绝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("---------------结束测试-------------------")