前言

接着上一篇的故事工厂模式继续,手机要出厂,显然光一个手机肯定是不行的,还需要包装盒、充电器等等东西。我们按照上一篇提到的工厂模式,去建立新的工厂是一点都没有问题的。但是思考一下这样子做会带来的问题,显然工厂太多了,将包装盒、充电器全部分散到各个工厂,组装什么的也是一个大问题,那么有没有更好的办法呢?答案是肯定的,抽象工厂模式

抽象工厂意图

提供一个创建一系列相关或相互依赖对象的接口,而无需制定它们具体的累。

别名

Kit

案例

第三阶段

光生产手机远远不够,还需要生产其他配件,分散到新的工厂成本太高,也不利于维护,那就把一个类型的手机所需要的所有东西,都放到一个工厂完成,小米工厂生产小米手机以及小米手机配套的东西,苹果手机生产苹果手机以及苹果手机配套的东西,客户只需要关心要什么手机就行了。

第三阶段 UML 图

让我们借助 UML 图直观了解一下这个时候工厂的样子

第三阶段代码

通过代码去实现这个逻辑

from abc import ABC, abstractmethod

# 抽象手机
class AbstractMobile(ABC): @abstractmethod
def make(self):
pass class XiaoMiMobile(AbstractMobile): def make(self):
print("make xiaomi mobile") class AppleMobile(AbstractMobile): def make(self):
print("make apple mobile") # 抽象手机配件
class AbstractOthers(ABC): @abstractmethod
def make(self):
pass class XiaoMiOthers(AbstractMobile): def make(self):
print("make xiaomi others") class AppleOthers(AbstractMobile): def make(self):
print("make apple others") # 抽象工厂
class AbstractFactory(ABC):
@abstractmethod
def create_mobile(self) -> AbstractMobile:
pass @abstractmethod
def create_others(self) -> AbstractOthers:
pass class XiaoMiFactory(AbstractFactory): def create_mobile(self) -> XiaoMiMobile:
return XiaoMiMobile().make() def create_others(self) -> XiaoMiOthers:
return XiaoMiOthers().make() class AppleFactory(AbstractFactory): def create_mobile(self) -> AppleMobile:
return AppleMobile().make() def create_others(self) -> AppleOthers:
return AppleOthers().make() def client(factory: AbstractFactory) -> None:
product_mobile = factory.create_mobile()
product_others = factory.create_others() if __name__ == "__main__":
client(XiaoMiFactory())
client(AppleFactory())

看一下运行结果:

make xiaomi mobile
make xiaomi others
make apple mobile
make apple others

总结

如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。
在设计良好的程序中, 每个类仅负责一件事。 如果一个类与多种类型产品交互, 就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。

抽象工厂的优缺点

优点

  • 你可以确保同一工厂生成的产品相互匹配。
  • 你可以避免客户端和具体产品代码的耦合。
  • 单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护。
  • 开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码

缺点

  • 由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂,即产品族扩展非常困难

最新文章

  1. CentOS7 Jenkins安装
  2. HTML核心元素
  3. .bash_profile for mac‘ envionment variables
  4. SqlServer中的更新锁(UPDLOCK)
  5. COJ 0801 非传统题(一)
  6. 水池(DFS)
  7. auDemo
  8. springboot小技巧(转)
  9. NOIP-玩具谜题
  10. HTTP协议 (1)
  11. .net 技术地图
  12. 高并发分布式系统中生成全局唯一(订单号)Id js返回上一页并刷新、返回上一页、自动刷新页面 父页面操作嵌套iframe子页面的HTML标签元素 .net判断System.Data.DataRow中是否包含某列 .Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数
  13. Mysql截取和拆分字符串函数用法
  14. HDU 3472 混合图欧拉回路 + 网络流
  15. 社区发现的3个评估指标:标准化互信息NMI,ARI指标,以及模块度(modularity)
  16. pandas模块安装问题笔记
  17. windows命令行快捷操作
  18. wamp5多站点配置教程
  19. c++11 on Android
  20. asp.net mvc3.0安装失败之终极解决方案

热门文章

  1. Express4.x之中间件与路由详解及源码分析
  2. SpringMVC的url-pattern配置及原理剖析
  3. LeetCode 77,组合挑战,你能想出不用递归的解法吗?
  4. 使用三台云服务器搭建真正的Redis集群
  5. winXP vc6行号显示插件-VC6LineNumberAddin方法-可用-无需注册
  6. 阿里云Ubuntu配置mysql+navicat连接
  7. int与Integer的区别(基本类型与复杂类型的对比)转
  8. Windows 安装RabbitMQ后,启动服务就自动停止
  9. 详述@Responsebody和HTTP异步请求的关系
  10. skywalking面板功能介绍2