2025/9/17日 每日总结工厂方法模式实战:构建可扩展加密算法系统

工厂方法模式实战:构建可扩展加密算法系统

在软件开发中,当需要支持多种同类功能(如不同加密算法、支付方式、日志框架)时,简单工厂模式的"单一工厂+多产品"结构会导致工厂类职责过重,难以维护。工厂方法模式通过"一个产品对应一个工厂"的设计,完美解决了这一问题,实现了更高的灵活性和扩展性。本文将通过DES和IDEA两种加密算法的实战开发,带你吃透工厂方法模式的核心思想与落地技巧。

一、模式核心:为什么需要工厂方法?

简单工厂模式的核心问题在于工厂类与产品类强耦合——新增产品时必须修改工厂类的判断逻辑,违反了"开闭原则"。而工厂方法模式的设计动机正是:

  1. 将对象创建逻辑分散到各个具体工厂,避免单一工厂职责过重
  2. 新增产品时无需修改现有代码,只需新增产品类和对应的工厂类
  3. 客户端通过选择不同工厂来获取不同产品,无需关心产品创建细节
    工厂方法模式的核心结构包含四个角色:
  • 抽象产品(Product):定义产品的公共接口(如加密算法的加密/解密行为)

  • 具体产品(ConcreteProduct):实现抽象产品接口(如DES、IDEA算法)

  • 抽象工厂(Factory):定义工厂的公共接口(如创建加密算法的方法)

  • 具体工厂(ConcreteFactory):实现抽象工厂接口,负责创建对应具体产品(如DES工厂、IDEA工厂)

    二、场景分析:加密算法系统需求

    我们需要构建一个支持多种加密算法的系统,核心需求如下:

  1. 支持DES和IDEA两种对称加密算法

  2. 每种算法需实现"加密+解密"核心功能

  3. 系统可灵活扩展新算法(如AES、RSA),无需修改现有代码

  4. 客户端可通过简单配置选择不同加密算法
    根据工厂方法模式的设计思路,我们将系统拆分为"抽象工厂+具体工厂+抽象产品+具体产品"四层结构,确保各组件职责单一、低耦合。

三、代码实现:一步步构建加密系统

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 │ <-- 客户端(主程序)
└─────────────────┘

五、模式优缺点与适用场景

优点

  1. 符合开闭原则:新增加密算法时,只需新增"具体产品+具体工厂",无需修改现有代码

  2. 职责单一:每个工厂只负责创建一种产品,工厂类逻辑清晰,易于维护

  3. 解耦效果更好:客户端仅依赖抽象工厂和抽象产品,与具体实现完全分离

  4. 扩展性强:支持横向扩展(新增产品)和纵向扩展(修改产品实现)

缺点

  1. 类数量增多:每种产品都需要对应一个工厂类,当产品数量较多时,类文件会增多

  2. 复杂度提升:相比简单工厂模式,增加了抽象工厂和具体工厂的层级,理解成本稍高

  3. 客户端需了解工厂:客户端需要知道不同工厂对应的产品,才能选择合适的工厂

适用场景

  1. 产品种类较多且可能持续扩展(如加密算法、支付方式、日志框架)

  2. 希望客户端与具体产品解耦,无需关心产品创建细节

  3. 要求系统严格遵循开闭原则,支持灵活扩展

六、扩展与优化: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>
    

    七、总结与思考

    工厂方法模式是简单工厂模式的优化升级,其核心价值在于通过抽象化设计实现系统的可扩展性。通过本次加密算法系统的实战,我们可以得出以下关键结论:

  1. 工厂方法模式的核心是"抽象工厂+具体工厂"的分层设计,将对象创建逻辑分散,避免单一工厂职责过重。
  2. 该模式完美遵循开闭原则,新增产品时只需新增"具体产品+具体工厂",无需修改现有代码,特别适合产品种类较多且可能扩展的场景。
  3. 与简单工厂模式相比,工厂方法模式的解耦效果更彻底,但代价是类数量增多,需在扩展性和复杂度之间做平衡。
    在实际开发中,工厂方法模式的应用场景非常广泛,例如:
  • 支付系统:支付宝、微信支付、银联支付分别对应不同工厂
  • 日志系统:文件日志、数据库日志、控制台日志分别对应不同工厂
  • 缓存系统:Redis、Memcached、本地缓存分别对应不同工厂
    通过本次实验,深刻体会到设计模式的本质是"解决特定问题的最佳实践"。掌握工厂方法模式,不仅能写出更灵活、可维护的代码,更能培养"面向抽象编程"的思维方式——这是从初级开发者向中级开发者进阶的关键一步。
    如果需要进一步扩展该系统,只需新增具体产品(如AES算法)和对应的具体工厂(AESFactory),无需修改客户端和现有工厂代码,充分体现了工厂方法模式的扩展性优势。
posted @ 2025-11-13 09:09  Moonbeamsc  阅读(13)  评论(0)    收藏  举报
返回顶端