2025/9/17日 每日总结工厂方法模式实战:构建可扩展加密算法系统
工厂方法模式实战:构建可扩展加密算法系统
在软件开发中,当需要支持多种同类功能(如不同加密算法、支付方式、日志框架)时,简单工厂模式的"单一工厂+多产品"结构会导致工厂类职责过重,难以维护。工厂方法模式通过"一个产品对应一个工厂"的设计,完美解决了这一问题,实现了更高的灵活性和扩展性。本文将通过DES和IDEA两种加密算法的实战开发,带你吃透工厂方法模式的核心思想与落地技巧。
一、模式核心:为什么需要工厂方法?
简单工厂模式的核心问题在于工厂类与产品类强耦合——新增产品时必须修改工厂类的判断逻辑,违反了"开闭原则"。而工厂方法模式的设计动机正是:
- 将对象创建逻辑分散到各个具体工厂,避免单一工厂职责过重
- 新增产品时无需修改现有代码,只需新增产品类和对应的工厂类
- 客户端通过选择不同工厂来获取不同产品,无需关心产品创建细节
工厂方法模式的核心结构包含四个角色:
-
抽象产品(Product):定义产品的公共接口(如加密算法的加密/解密行为)
-
具体产品(ConcreteProduct):实现抽象产品接口(如DES、IDEA算法)
-
抽象工厂(Factory):定义工厂的公共接口(如创建加密算法的方法)
-
具体工厂(ConcreteFactory):实现抽象工厂接口,负责创建对应具体产品(如DES工厂、IDEA工厂)
二、场景分析:加密算法系统需求
我们需要构建一个支持多种加密算法的系统,核心需求如下:
-
支持DES和IDEA两种对称加密算法
-
每种算法需实现"加密+解密"核心功能
-
系统可灵活扩展新算法(如AES、RSA),无需修改现有代码
-
客户端可通过简单配置选择不同加密算法
根据工厂方法模式的设计思路,我们将系统拆分为"抽象工厂+具体工厂+抽象产品+具体产品"四层结构,确保各组件职责单一、低耦合。
三、代码实现:一步步构建加密系统
1. 定义抽象产品接口(Method)
抽象产品接口定义了所有加密算法的公共行为,即work方法(包含加密、解密逻辑),所有具体加密算法都需实现该接口。
package jiami;
// 抽象产品:加密算法接口
public interface Method {
// 核心方法:接收明文/密文和密钥,执行加密/解密
void work(String str, String password);
}
2. 实现具体产品类
分别实现DES和IDEA两种具体加密算法,基于Java加密库(JCE)和第三方依赖(BouncyCastle)完成真实的加密/解密逻辑。
2.1 DES加密算法实现(DES.java)
DES是经典的对称加密算法,使用56位密钥对64位数据块进行加密,以下是完整实现:
package jiami;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
// 具体产品:DES加密算法
public class DES implements Method {
@Override
public void work(String str, String password) {
String plaintext = "加密测试明文";
String cipherType = "DESede"; // 增强型DES算法
System.out.println("=== DES加密算法执行 ===");
System.out.println("原始明文:" + plaintext);
try {
// 生成密钥
KeyGenerator keyGen = KeyGenerator.getInstance(cipherType);
keyGen.init(112); // 密钥长度112位
SecretKey key = keyGen.generateKey();
byte[] keyBytes = key.getEncoded();
// 打印密钥信息
System.out.print("生成密钥(字节数组):");
for (byte b : keyBytes) {
System.out.print(b + " ");
}
System.out.println();
// 初始化加密器
Cipher cipher = Cipher.getInstance(cipherType);
cipher.init(Cipher.ENCRYPT_MODE, key);
// 加密过程
byte[] plaintextBytes = plaintext.getBytes("UTF-8");
System.out.print("明文字节数组:");
for (byte b : plaintextBytes) {
System.out.print(b + " ");
}
System.out.println();
byte[] ciphertextBytes = cipher.doFinal(plaintextBytes);
System.out.print("加密后字节数组:");
for (byte b : ciphertextBytes) {
System.out.print(b + " ");
}
System.out.println();
System.out.println("加密后字符串:" + new String(ciphertextBytes));
// 解密过程
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedBytes = cipher.doFinal(ciphertextBytes);
System.out.print("解密后字节数组:");
for (byte b : decryptedBytes) {
System.out.print(b + " ");
}
System.out.println();
System.out.println("解密后字符串:" + new String(decryptedBytes, "UTF-8"));
} catch (Exception e) {
System.err.println("DES算法执行异常:" + e.getMessage());
e.printStackTrace();
}
}
// 测试方法
public static void main(String[] args) {
DES des = new DES();
des.work("明文", "密钥");
}
}
#### 2.2 IDEA加密算法实现(IDEA.java)
IDEA算法安全性高于DES,使用128位密钥,需引入BouncyCastle依赖支持,完整实现如下:
```java
package jiami;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Key;
import java.security.Security;
// 具体产品:IDEA加密算法
public class IDEA implements Method {
// 算法常量定义
public static final String KEY_ALGORITHM = "IDEA";
public static final String CIPHER_ALGORITHM = "IDEA/ECB/ISO10126Padding";
// 初始化密钥
private static byte[] initKey() throws Exception {
Security.addProvider(new BouncyCastleProvider()); // 引入第三方加密提供者
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
kg.init(128); // IDEA密钥长度128位
SecretKey secretKey = kg.generateKey();
return secretKey.getEncoded();
}
// 密钥转换
private static Key toKey(byte[] key) throws Exception {
return new SecretKeySpec(key, KEY_ALGORITHM);
}
// 加密核心方法
private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
Security.addProvider(new BouncyCastleProvider());
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, k);
return cipher.doFinal(data);
}
// 解密核心方法
private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
Security.addProvider(new BouncyCastleProvider());
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, k);
return cipher.doFinal(data);
}
// 生成Base64编码的密钥
public static String getKey() {
try {
return Base64.encodeBase64String(initKey());
} catch (Exception e) {
System.err.println("密钥生成失败:" + e.getMessage());
return null;
}
}
// 对外提供加密接口(Base64编码密文,便于传输)
public static String ideaEncrypt(String data, String key) {
try {
byte[] encryptedData = encrypt(data.getBytes(), Base64.decodeBase64(key));
return Base64.encodeBase64String(encryptedData);
} catch (Exception e) {
System.err.println("IDEA加密失败:" + e.getMessage());
return null;
}
}
// 对外提供解密接口
public static String ideaDecrypt(String data, String key) {
try {
byte[] decryptedData = decrypt(Base64.decodeBase64(data), Base64.decodeBase64(key));
return new String(decryptedData);
} catch (Exception e) {
System.err.println("IDEA解密失败:" + e.getMessage());
return null;
}
}
@Override
public void work(String str, String password) {
String plaintext = "加密测试明文";
String key = getKey();
System.out.println("=== IDEA加密算法执行 ===");
System.out.println("原始明文:" + plaintext);
System.out.println("生成密钥(Base64编码):" + key);
// 加密
String ciphertext = ideaEncrypt(plaintext, key);
System.out.println("加密后密文(Base64编码):" + ciphertext);
// 解密
String decryptedText = ideaDecrypt(ciphertext, key);
System.out.println("解密后明文:" + decryptedText);
}
// 测试方法
public static void main(String[] args) {
IDEA idea = new IDEA();
idea.work("明文", "密钥");
}
}
3. 定义抽象工厂接口(MethodFactory)
抽象工厂接口定义了创建加密算法对象的公共方法produceMethod,所有具体工厂都需实现该接口,返回对应的具体产品实例。
package jiami;
// 抽象工厂:加密算法工厂接口
public interface MethodFactory {
// 工厂方法:创建对应的加密算法对象
Method produceMethod();
}
4. 实现具体工厂类
为每种加密算法创建对应的具体工厂,负责创建该算法的实例,实现了"一个产品对应一个工厂"的设计。
4.1 DES工厂(DESFactory.java)
package jiami;
// 具体工厂:DES算法工厂
public class DESFactory implements MethodFactory {
@Override
public Method produceMethod() {
System.out.println("创建DES加密算法实例");
return new DES();
}
}
4.2 IDEA工厂(IDEAFactory.java)
package jiami;
// 具体工厂:IDEA算法工厂
public class IDEAFactory implements MethodFactory {
@Override
public Method produceMethod() {
System.out.println("创建IDEA加密算法实例");
return new IDEA();
}
}
5. 客户端调用(主程序)
客户端通过选择不同的具体工厂,即可获取对应的加密算法实例,无需直接创建产品对象,实现了"创建与使用分离"。
package jiami;
import java.util.Scanner;
// 客户端:加密算法系统主程序
public class zhuhanshu {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int choice = 0;
System.out.println("=== 加密算法系统 ===");
System.out.println("1. 使用DES加密算法");
System.out.println("2. 使用IDEA加密算法");
System.out.println("3. 退出系统");
while (choice != 3) {
System.out.print("\n请输入选择(1-3):");
if (scanner.hasNextInt()) {
choice = scanner.nextInt();
scanner.nextLine(); // 清除换行符
} else {
System.out.println("输入无效,请输入整数!");
scanner.nextLine();
continue;
}
MethodFactory factory = null;
switch (choice) {
case 1:
factory = new DESFactory(); // 选择DES工厂
break;
case 2:
factory = new IDEAFactory(); // 选择IDEA工厂
break;
case 3:
System.out.println("退出系统,感谢使用!");
continue;
default:
System.out.println("选择无效,请重新输入!");
continue;
}
// 工厂创建产品,执行加密/解密
Method encryptionMethod = factory.produceMethod();
encryptionMethod.work("明文", "密钥");
}
scanner.close();
}
}
四、可视化类图设计
工厂方法模式的结构关系通过类图可直观展示:
┌─────────────────┐
│ Method │ <-- 抽象产品(加密算法接口)
│─────────────────│
│ + work(str: String, password: String): void │
└─────────────────┘
↑
│ 实现
┌─────────────────┐ ┌─────────────────┐
│ DES │ │ IDEA │ <-- 具体产品(加密算法实现)
│─────────────────│ │─────────────────│
│ + work(...): void │ │ + work(...): void │
└─────────────────┘ └─────────────────┘
↑ ↑
│ 创建 │ 创建
┌─────────────────┐ ┌─────────────────┐
│ DESFactory │ │ IDEAFactory │ <-- 具体工厂(算法创建者)
│─────────────────│ │─────────────────│
│ + produceMethod(): Method │ │ + produceMethod(): Method │
└─────────────────┘ └─────────────────┘
↑ ↑
│ 实现 │ 实现
┌─────────────────┐
│ MethodFactory │ <-- 抽象工厂(工厂接口)
│─────────────────│
│ + produceMethod(): Method │
└─────────────────┘
↑
│ 调用
┌─────────────────┐
│ zhuhanshu │ <-- 客户端(主程序)
└─────────────────┘
五、模式优缺点与适用场景
优点
-
符合开闭原则:新增加密算法时,只需新增"具体产品+具体工厂",无需修改现有代码
-
职责单一:每个工厂只负责创建一种产品,工厂类逻辑清晰,易于维护
-
解耦效果更好:客户端仅依赖抽象工厂和抽象产品,与具体实现完全分离
-
扩展性强:支持横向扩展(新增产品)和纵向扩展(修改产品实现)
缺点
-
类数量增多:每种产品都需要对应一个工厂类,当产品数量较多时,类文件会增多
-
复杂度提升:相比简单工厂模式,增加了抽象工厂和具体工厂的层级,理解成本稍高
-
客户端需了解工厂:客户端需要知道不同工厂对应的产品,才能选择合适的工厂
适用场景
-
产品种类较多且可能持续扩展(如加密算法、支付方式、日志框架)
-
希望客户端与具体产品解耦,无需关心产品创建细节
-
要求系统严格遵循开闭原则,支持灵活扩展
六、扩展与优化:HTML交互式演示系统
为了更直观地展示加密系统的使用效果,我们开发了HTML交互式演示页面,支持用户选择算法、输入明文和密钥,实时查看加密/解密结果。
核心功能:
-
支持DES和IDEA算法切换
-
明文/密钥输入框,支持自定义内容
-
加密/解密按钮,实时展示结果
-
算法介绍模块,普及加密知识
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>加密算法演示系统</title> <style> /* 样式省略,保持页面美观易操作 */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif; } body { background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); color: #333; min-height: 100vh; display: flex; justify-content: center; padding: 20px; } .container { width: 90%; max-width: 1000px; background: rgba(255,255,255,0.92); border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); overflow: hidden; } header { background: linear-gradient(to right, #2c3e50, #4a6491); color: white; padding: 25px; text-align: center; } .content { display: flex; flex-wrap: wrap; padding: 20px; } .algorithm-info, .algorithm-demo { flex: 1; min-width: 300px; padding: 20px; margin: 10px; background: #f8f9fa; border-radius: 10px; } .algorithm-selector { display: flex; margin-bottom: 20px; } .algorithm-btn { flex: 1; padding: 12px; border: none; background: #e9ecef; cursor: pointer; font-weight: 600; } .algorithm-btn.active { background: #4a6491; color: white; } .input-group { margin-bottom: 20px; } textarea, input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 16px; } .btn-group { display: flex; gap: 10px; } button { flex: 1; padding: 12px; background: #4a6491; color: white; border: none; border-radius: 6px; cursor: pointer; } .result { background: #e9ecef; padding: 15px; border-radius: 6px; margin-top: 20px; } </style> </head> <body> <div class="container"> <header> <h1>加密算法演示系统</h1> <p>基于工厂方法模式的DES和IDEA加密算法实现</p> </header> <div class="content"> <div class="algorithm-info"> <h2>算法介绍</h2> <h3>DES算法</h3> <p>Data Encryption Standard,对称密钥加密算法,使用56位密钥,64位数据块加密,适用于中等安全需求场景。</p> <h3>IDEA算法</h3> <p>International Data Encryption Algorithm,对称密钥块加密算法,128位密钥,安全性高于DES,适用于高安全需求场景。</p> <h3>工厂方法模式</h3> <p>通过"抽象工厂+具体工厂+抽象产品+具体产品"结构,实现加密算法的灵活扩展,新增算法无需修改现有代码。</p> </div> <div class="algorithm-demo"> <h2>算法演示</h2> <div class="algorithm-selector"> <button class="algorithm-btn active" data-algorithm="des">DES算法</button> <button class="algorithm-btn" data-algorithm="idea">IDEA算法</button> </div> <div class="input-group"> <label for="plaintext">明文:</label> <textarea id="plaintext" rows="3" placeholder="请输入要加密的文本">测试加密内容</textarea> </div> <div class="input-group"> <label for="key">密钥(可选):</label> <input id="key" type="text" placeholder="DES填56位密钥,IDEA填128位密钥"> </div> <div class="btn-group"> <button id="encrypt-btn">加密</button> <button id="decrypt-btn">解密</button> <button id="reset-btn">重置</button> </div> <div class="result"> <h3>加密结果:</h3> <pre id="encryption-result">请点击加密按钮查看结果</pre> </div> <div class="result"> <h3>解密结果:</h3> <pre id="decryption-result">加密后自动显示解密结果</pre> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const algorithmBtns = document.querySelectorAll('.algorithm-btn'); const encryptBtn = document.getElementById('encrypt-btn'); const decryptBtn = document.getElementById('decrypt-btn'); const resetBtn = document.getElementById('reset-btn'); const plaintextInput = document.getElementById('plaintext'); const keyInput = document.getElementById('key'); const encryptionResult = document.getElementById('encryption-result'); const decryptionResult = document.getElementById('decryption-result'); let currentAlgorithm = 'des'; // 切换算法 algorithmBtns.forEach(btn => { btn.addEventListener('click', function() { algorithmBtns.forEach(b => b.classList.remove('active')); this.classList.add('active'); currentAlgorithm = this.getAttribute('data-algorithm'); keyInput.placeholder = currentAlgorithm === 'des' ? 'DES算法密钥(可选,56位)' : 'IDEA算法密钥(可选,128位)'; }); }); // 加密逻辑(前端模拟,真实场景需调用后端接口) encryptBtn.addEventListener('click', function() { const plaintext = plaintextInput.value.trim(); if (!plaintext) { alert('请输入明文!'); return; } let encrypted = ''; if (currentAlgorithm === 'des') { encrypted = `DES加密成功\n密钥:${keyInput.value || '默认56位密钥'}\n密文(Base64):${btoa(plaintext)}`; } else { encrypted = `IDEA加密成功\n密钥:${keyInput.value || '默认128位密钥'}\n密文(Base64):${btoa(plaintext)}`; } encryptionResult.textContent = encrypted; // 自动解密 decryptBtn.click(); }); // 解密逻辑 decryptBtn.addEventListener('click', function() { const ciphertext = encryptionResult.textContent; if (ciphertext === '请点击加密按钮查看结果') { alert('请先执行加密!'); return; } const base64Str = ciphertext.split('\n')[2].split(':')[1]; const decrypted = atob(base64Str); decryptionResult.textContent = `${currentAlgorithm.toUpperCase()}解密成功\n明文:${decrypted}`; }); // 重置 resetBtn.addEventListener('click', function() { plaintextInput.value = '测试加密内容'; keyInput.value = ''; encryptionResult.textContent = '请点击加密按钮查看结果'; decryptionResult.textContent = '加密后自动显示解密结果'; }); }); </script> </body> </html>七、总结与思考
工厂方法模式是简单工厂模式的优化升级,其核心价值在于通过抽象化设计实现系统的可扩展性。通过本次加密算法系统的实战,我们可以得出以下关键结论:
- 工厂方法模式的核心是"抽象工厂+具体工厂"的分层设计,将对象创建逻辑分散,避免单一工厂职责过重。
- 该模式完美遵循开闭原则,新增产品时只需新增"具体产品+具体工厂",无需修改现有代码,特别适合产品种类较多且可能扩展的场景。
- 与简单工厂模式相比,工厂方法模式的解耦效果更彻底,但代价是类数量增多,需在扩展性和复杂度之间做平衡。
在实际开发中,工厂方法模式的应用场景非常广泛,例如:
- 支付系统:支付宝、微信支付、银联支付分别对应不同工厂
- 日志系统:文件日志、数据库日志、控制台日志分别对应不同工厂
- 缓存系统:Redis、Memcached、本地缓存分别对应不同工厂
通过本次实验,深刻体会到设计模式的本质是"解决特定问题的最佳实践"。掌握工厂方法模式,不仅能写出更灵活、可维护的代码,更能培养"面向抽象编程"的思维方式——这是从初级开发者向中级开发者进阶的关键一步。
如果需要进一步扩展该系统,只需新增具体产品(如AES算法)和对应的具体工厂(AESFactory),无需修改客户端和现有工厂代码,充分体现了工厂方法模式的扩展性优势。

浙公网安备 33010602011771号