【软考设计模式】简单工厂模式:多形态实现与代码填空精讲

📅 2026/7/16 5:35:43 👁️ 阅读次数 📝 编程学习
【软考设计模式】简单工厂模式:多形态实现与代码填空精讲

【软考设计模式】简单工厂模式:多形态实现与代码填空精讲

系列定位:软考软件设计师 / 系统架构设计师 — 创建型模式专题第 1 讲
考察分值:上午题 1-2 分,下午题常结合代码填空出现
难度等级:⭐⭐☆☆☆(基础必拿分)


一、考纲定位与模式定义

1.1 考纲要求

简单工厂模式在软考中属于创建型模式的入门内容。考察形式包括:

  • 上午选择题:判断描述所属模式;识别简单工厂与工厂方法的区别

  • 下午设计题:补全工厂类的创建逻辑;根据类图写出工厂方法返回值

1.2 模式定义

简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。

核心意图:将对象的创建逻辑从客户端抽离,实现"创建与使用分离"


二、UML 类图与角色划分

┌─────────────────────────────────────────────┐ │ Client │ │ + main() │ └─────────────────────┬───────────────────────┘ │ uses ▼ ┌─────────────────────────────────────────────┐ │ SimpleFactory │ │ + createProduct(type): Product │ └─────────────────────┬───────────────────────┘ │ creates ┌───────────┴───────────┐ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ <<interface>> │ │ <<interface>> │ │ Product │◄────│ Product │ │ + operation() │ │ + operation() │ └─────────────────┘ └─────────────────┘ △ △ │ │ ┌──────┴─────────┐ ┌──────┴─────────┐ │ │ │ │ ┌──┴─────┐ ┌────┴───┐ ┌──┴─────┐ ┌────┴───┐ │Concrete│ │Concrete│ │Concrete│ │Concrete│ │ProductA│ │ProductB│ │ProductC│ │ProductD│ └────────┘ └────────┘ └────────┘ └────────┘
角色职责软考填空关键词
Product抽象产品,定义接口interface/abstract class
ConcreteProduct具体产品,实现接口实现类名
SimpleFactory工厂类,负责创建实例create()/getInstance()
Client通过工厂获取产品面向接口调用方法

三、场景一:文件解析器(接口 + 分支判断)

业务背景:系统需要解析 PDF、Excel、Word 三种文件格式,解析逻辑由工厂统一创建。

说明:这里采用了先定义接口,再实现接口,最后使用if else的方式实现工厂类。

3.1 代码实现

// 抽象产品:接口 interface FileParser { void parse(String filePath); } // 具体产品 class PdfParser implements FileParser { public void parse(String filePath) { System.out.println("解析 PDF 文件: " + filePath); } } class ExcelParser implements FileParser { public void parse(String filePath) { System.out.println("解析 Excel 文件: " + filePath); } } class WordParser implements FileParser { public void parse(String filePath) { System.out.println("解析 Word 文件: " + filePath); } } // 工厂类:使用 if-else 分支判断 class ParserFactory { public static FileParser createParser(String ext) { if ("pdf".equalsIgnoreCase(ext)) { return new PdfParser(); } else if ("excel".equalsIgnoreCase(ext) || "xlsx".equalsIgnoreCase(ext)) { return new ExcelParser(); } else if ("word".equalsIgnoreCase(ext) || "docx".equalsIgnoreCase(ext)) { return new WordParser(); } throw new IllegalArgumentException("不支持的文件格式: " + ext); } } // 客户端 public class ParserClient { public static void main(String[] args) { String extension = "pdf"; // 来自文件上传组件 FileParser parser = ParserFactory.createParser(extension); parser.parse("/data/report.pdf"); } }

四、场景二:缓存策略(抽象类 + Map 注册)

业务背景:系统支持内存缓存、Redis 缓存、磁盘缓存三种策略,通过 Map 预先注册,避免分支判断。

说明:这里采用了先定义抽象类,再将抽象类拓展为不同的具体类,最后使用Map注册的方式实现工厂类。

4.1 代码实现

import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; // 抽象产品:抽象类(可含公共字段/方法) abstract class Cache { protected String name; public Cache(String name) { this.name = name; } public abstract void put(String key, Object value); public abstract Object get(String key); } // 具体产品 class MemoryCache extends Cache { public MemoryCache() { super("Memory"); } public void put(String key, Object value) { System.out.println("[" + name + "] 写入: " + key); } public Object get(String key) { System.out.println("[" + name + "] 读取: " + key); return null; } } class RedisCache extends Cache { public RedisCache() { super("Redis"); } public void put(String key, Object value) { System.out.println("[" + name + "] 写入: " + key); } public Object get(String key) { System.out.println("[" + name + "] 读取: " + key); return null; } } class DiskCache extends Cache { public DiskCache() { super("Disk"); } public void put(String key, Object value) { System.out.println("[" + name + "] 写入: " + key); } public Object get(String key) { System.out.println("[" + name + "] 读取: " + key); return null; } } // 工厂类:使用 Map + Supplier 注册(Java 8+) class CacheFactory { private static final Map<String, Supplier<Cache>> registry = new HashMap<>(); // 静态注册 static { // 构造器引用(类名::new) registry.put("memory", MemoryCache::new); registry.put("redis", RedisCache::new); registry.put("disk", DiskCache::new); } public static Cache createCache(String type) { // 通过registry.get(type)获取Supplier<Cache>对象 Supplier<Cache> supplier = registry.get(type); if (supplier == null) { throw new IllegalArgumentException("未知缓存类型: " + type); } return supplier.get(); } } // 客户端 public class CacheClient { public static void main(String[] args) { Cache cache = CacheFactory.createCache("redis"); cache.put("user:1001", "张三"); } }

五、场景三:数据加密(接口 + 配置文件反射)

业务背景:系统支持 AES、RSA、SM4 等加密算法,算法类名写在配置文件中,工厂通过反射动态创建,新增算法无需修改工厂代码

5.1 代码实现

import java.io.InputStream; import java.util.Properties; // 抽象产品:接口 interface Encryptor { String encrypt(String plainText); String decrypt(String cipherText); } // 具体产品 class AesEncryptor implements Encryptor { public String encrypt(String plainText) { return "AES(" + plainText + ")"; } public String decrypt(String cipherText) { return "AES-decrypt(" + cipherText + ")"; } } class RsaEncryptor implements Encryptor { public String encrypt(String plainText) { return "RSA(" + plainText + ")"; } public String decrypt(String cipherText) { return "RSA-decrypt(" + cipherText + ")"; } } class Sm4Encryptor implements Encryptor { public String encrypt(String plainText) { return "SM4(" + plainText + ")"; } public String decrypt(String cipherText) { return "SM4-decrypt(" + cipherText + ")"; } } // 工厂类:通过配置文件 + 反射创建 class EncryptorFactory { private static final Properties config = new Properties(); static { try (InputStream is = EncryptorFactory.class .getClassLoader() .getResourceAsStream("encrypt.properties")) { config.load(is); } catch (Exception e) { throw new RuntimeException("加载配置失败", e); } } public static Encryptor createEncryptor(String name) { String className = config.getProperty(name); if (className == null) { throw new IllegalArgumentException("未配置: " + name); } try { Class<?> clazz = Class.forName(className); return (Encryptor) clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException("创建失败: " + className, e); } } } // 配置文件 encrypt.properties(放在 classpath 下) // aes=com.example.AesEncryptor // rsa=com.example.RsaEncryptor // sm4=com.example.Sm4Encryptor // 客户端 public class EncryptClient { public static void main(String[] args) { Encryptor encryptor = EncryptorFactory.createEncryptor("aes"); String result = encryptor.encrypt("敏感数据"); System.out.println(result); } }

六、三种实现方式对比

维度场景一:分支判断场景二:Map 注册场景三:反射配置
抽象产品interfaceabstract classinterface
创建方式if-else/switchMap<String, Supplier>Class.forName()+ 配置文件
扩展性差(新增需改工厂)中(新增需改 Map 注册)优(新增只需改配置文件)
软考适用基础代码填空考察 Java 8 特性考察反射与配置化
复杂度

七、软考高频考点与易混淆辨析

7.1 高频考点

考点内容
模式分类创建型模式(非 GoF 23 正式成员,是工厂方法的简化)
核心优点① 客户端与具体产品解耦 ② 创建逻辑集中管理
核心缺点违背开闭原则(OCP):新增产品需修改工厂类(场景一、二);场景三通过反射可缓解
返回值类型必须是抽象产品Product接口或抽象类),不能是具体类
客户端编程面向抽象产品编程,如Product p = Factory.create("xxx")

7.2 易混淆辨析:简单工厂 vs 工厂方法

对比项简单工厂工厂方法
工厂数量一个工厂类一个产品对应一个具体工厂
产品扩展修改工厂类(违背 OCP)新增具体工厂类(符合 OCP)
结构复杂度简单较复杂
软考出现常作为代码填空基础题常作为下午设计大题

八、真题风格模拟与代码填空

模拟题 1(上午选择题)

以下关于简单工厂模式的叙述中,正确的是()。

A. 简单工厂是 GoF 23 种设计模式之一
B. 简单工厂新增产品时,无需修改任何现有代码即可扩展
C. 简单工厂中,客户端应直接实例化具体产品类以提高效率
D. 简单工厂将对象的创建逻辑集中到工厂类,降低了客户端与具体产品的耦合

答案:D

解析

  • A 错误:简单工厂不是GoF 23 种正式模式,工厂方法才是。

  • B 错误:简单工厂新增产品通常需要修改工厂类的分支判断,违背开闭原则。

  • C 错误:客户端应面向抽象产品编程,通过工厂获取实例。

  • D 正确:这是简单工厂的核心优点。


模拟题 2(下午代码填空)

某系统需要支持多种数据导出格式(PDF、Excel),使用简单工厂模式实现。请补全(1)~(3)。

interface ExportFile { void export(String data); } class PdfExport implements ExportFile { public void export(String data) { System.out.println("PDF: " + data); } } class ExcelExport implements ExportFile { public void export(String data) { System.out.println("Excel: " + data); } } class ExportFactory { public static (1)______ createExport(String type) { if ("pdf".equals(type)) { return (2)______; } else if ("excel".equals(type)) { return (3)______; } return null; } } public class Client { public static void main(String[] args) { ExportFile file = ExportFactory.createExport("pdf"); file.export("报表"); } }

答案

  • (1)ExportFile

  • (2)new PdfExport()

  • (3)new ExcelExport()


九、常见陷阱与注意事项

陷阱 1:误认为简单工厂是 GoF 正式模式

简单工厂不在GoF 23 种设计模式中。如果上午题问"以下属于 GoF 创建型模式的是",选项中出现"简单工厂"不能选

陷阱 2:工厂返回值写成具体类

软考代码填空时,工厂方法的返回值类型必须是抽象产品(接口或抽象类),如FileParser createParser(...)而非PdfParser createParser(...)

陷阱 3:忽视空指针判断

若工厂返回null,客户端直接调用方法会抛NullPointerException。规范写法应在工厂内抛异常,或客户端做非空判断。

陷阱 4:switch 与 if-else 的等价性

无论工厂内用switch还是if-else,软考阅卷均认可。但注意:Java 12+ 的switch表达式返回值更简洁,但软考通常按 Java 8 语法出题。

陷阱 5:与单例模式混淆

简单工厂可以返回单例对象(工厂内缓存实例),但简单工厂本身≠单例模式。不要看到"工厂只创建一个对象"就误判为单例。


十、总结

要点内容
定义一个工厂类根据参数创建不同实例,实例具有共同父类
分类创建型模式(非 GoF 正式成员,工厂方法的简化版)
实现形态接口/抽象类 + 分支判断 / Map 注册 / 反射配置
优点解耦、集中管理创建逻辑
缺点违背开闭原则(反射配置可缓解)
软考重点与工厂方法/抽象工厂的辨析;代码填空补全工厂类;识别类图角色
答题技巧看到"根据参数返回不同对象"且只有一个工厂类 → 选简单工厂