ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

设计模式02-工厂模式

2026/9/6 3:53:26 拓冰建站 浏览量
设计模式02-工厂模式 工厂模式把创建对象收进一个入口从一个真实的痛点出发业务代码里的 if-else 分发以及新增渠道时为什么总要改核心代码。一、痛点new 和 if-else 把代码焊死了假设我们有一个文件上传模块支持三种存储后端本地磁盘、阿里云 OSS、AWS S3。最直白的写法是这样publicStringupload(Stringfile,StringstorageType){if(local.equals(storageType)){returnnewLocalStorage().save(file);}elseif(oss.equals(storageType)){returnnewOssStorage().save(file);}elseif(s3.equals(storageType)){returnnewS3Storage().save(file);}thrownewIllegalArgumentException(未知存储类型: storageType);}这段代码的问题不是不能用而是经不起变化开闭原则被违反每新增一种存储后端比如七牛云就要回来改这段核心代码——对修改不封闭创建逻辑散落调用方必须知道每个实现类的名字和构造细节调用方被绑定业务代码与具体实现类强耦合换实现、做 Mock 都很痛苦。工厂模式的回答是把创建谁这个决策收口到一个专门的工厂类里调用方只面向接口。二、简单工厂一个入口屏蔽创建细节第一步改造抽出统一接口用工厂类承接创建逻辑。// 统一存储接口publicinterfaceStorageService{Stringsave(Stringfile);}publicclassLocalStorageimplementsStorageService{OverridepublicStringsave(Stringfile){returnlocal://file;}}// OssStorage、S3Storage 实现同构略importjava.util.HashMap;importjava.util.Map;importjava.util.function.Supplier;/** * 简单工厂唯一的创建入口 * 用注册表替代 if-else 链新增渠道时只动这一个类 */publicclassStorageFactory{privatestaticfinalMapString,SupplierStorageServiceREGISTRYnewHashMap();static{REGISTRY.put(local,LocalStorage::new);REGISTRY.put(oss,OssStorage::new);REGISTRY.put(s3,S3Storage::new);}publicstaticStorageServicecreate(Stringtype){SupplierStorageServicesupplierREGISTRY.get(type);if(suppliernull){thrownewIllegalArgumentException(不支持的存储类型: type);}returnsupplier.get();}}业务层彻底与实现类解耦publicclassFileService{publicStringupload(Stringfile,StringstorageType){StorageServicestorageStorageFactory.create(storageType);returnstorage.save(file);}}现在FileService不知道、也不需要知道 LocalStorage 和 OssStorage 的存在。它只依赖两个抽象StorageService接口和工厂的 create 方法。三、简单工厂的边界注意简单工厂把 if-else 从业务代码挪进了工厂类没有消灭 if-else只是把它集中了。这带来两个效果好处创建逻辑单点管理业务代码干净了代价新增渠道仍需修改工厂类加一行注册严格说没有完全满足开闭原则。如果新增渠道不改任何现有类是硬要求就需要工厂方法模式了。四、工厂方法一个产品一个工厂工厂方法的思路是把创建也抽象成接口每种产品对应一个独立工厂类。// 工厂接口GoF 术语中称为 CreatorpublicinterfaceStorageCreator{StorageServicecreate();}publicclassLocalStorageCreatorimplementsStorageCreator{OverridepublicStorageServicecreate(){returnnewLocalStorage();}}// OssStorageCreator、S3StorageCreator 同构略调用方持有工厂接口新增 S3 时写一个S3StorageCreator即可现有类零改动publicclassFileUploader{privatefinalStorageCreatorcreator;publicFileUploader(StorageCreatorcreator){this.creatorcreator;}publicStringupload(Stringfile){returncreator.create().save(file);}}代价也很明显类的数量翻倍——每个产品多一个工厂类。产品类型少时显得繁琐。五、两种工厂怎么选维度简单工厂工厂方法创建逻辑的位置集中在唯一工厂类分散到各产品专属工厂新增产品改工厂类加一行注册新增工厂类现有代码零修改类数量少每个产品多一个类开闭原则部分满足完全满足适用场景产品类型稳定、集中管理产品类型持续扩张、强调扩展性工程上的务实结论多数场景用简单工厂 注册表就够当产品线明显会持续扩张、且团队对改现有代码很敏感时升级到工厂方法。六、工厂模式没回答的问题工厂模式解决的是创建哪个对象它不解决创建完之后不同对象的行为差异怎么办。回到存储例子三种存储后端的 save 逻辑完全不同——这个差异由多态解决和工厂无关。如果业务里还有一类需求是根据参数选择执行哪套行为、并随时可切换那是策略模式的领地见本系列第 3 篇。这也是工厂和策略经常被一起提问的原因工厂管造策略管用。小结工厂模式的价值一句话创建入口收口调用方面向接口。简单工厂集中管理工厂方法彻底开闭。选哪个取决于产品类型的扩张预期和团队对类数量的容忍度。