【软考设计模式】简单工厂模式:多形态实现与代码填空精讲
【软考设计模式】简单工厂模式多形态实现与代码填空精讲系列定位软考软件设计师 / 系统架构设计师 — 创建型模式专题第 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 classConcreteProduct具体产品实现接口实现类名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 MapString, SupplierCache 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)获取SupplierCache对象 SupplierCache 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 下 // aescom.example.AesEncryptor // rsacom.example.RsaEncryptor // sm4com.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/switchMapString, SupplierClass.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。规范写法应在工厂内抛异常或客户端做非空判断。陷阱 4switch 与 if-else 的等价性无论工厂内用switch还是if-else软考阅卷均认可。但注意Java 12 的switch表达式返回值更简洁但软考通常按 Java 8 语法出题。陷阱 5与单例模式混淆简单工厂可以返回单例对象工厂内缓存实例但简单工厂本身≠单例模式。不要看到工厂只创建一个对象就误判为单例。十、总结要点内容定义一个工厂类根据参数创建不同实例实例具有共同父类分类创建型模式非 GoF 正式成员工厂方法的简化版实现形态接口/抽象类 分支判断 / Map 注册 / 反射配置优点解耦、集中管理创建逻辑缺点违背开闭原则反射配置可缓解软考重点与工厂方法/抽象工厂的辨析代码填空补全工厂类识别类图角色答题技巧看到根据参数返回不同对象且只有一个工厂类 → 选简单工厂

相关新闻