工厂模式

  • 概念
  • 实现
    • 简单工厂
    • 工厂方法
      • 工厂方法优点
    • 抽象工厂
  • 工厂方法和抽象工厂的比较

概念

在面向对象中,工厂表示一个负责创建其他类型对象的类。
工厂具有:

  • 松耦合
  • 客户端无需了解创建对象的类,但是照样可以使用它来创建对象。
  • 可以轻松的在工厂中添加其他类来创建其他类型的对象。

工厂模式有3种变体:

  • 简单工厂:允许接口创建对象,但不会暴露对象的创建逻辑。
  • 工厂方法:允许接口创建对象,但使用哪个类来创建对象是交给子类决定。
  • 抽象工厂:抽象工厂是一个能够创建一系列相关对象而无需指定其具体类的接口。它可以提供其他工厂的对象,在内部创建其他对象。

实现

简单工厂

  • 工厂根据传入的参数,返回或者创建不同的对象
# ABCMeta是Python的特殊的元类,用来生成抽象类
from abc import ABCMeta, abstractmethod# 动物类,定义say方法,但不实现
class Animal(metaclass=ABCMeta):@abstractmethoddef say(self):pass# 狗类,继承动物,重写say方法
class Dog(Animal):def say(self):print('i am dog')# 猫类,继承动物,重写say方法
class Cat(Animal):def say(self):print('i am cat')# 工厂类
class ForestFactory(object):# say方法的统一接口,传入子类对象,调用他们的say方法def say_something(self, object_type):return eval(object_type)().say()if __name__ == '__main__':ff = ForestFactory()animal = 'Cat'ff.say_something(animal)'''结果i am cat'''

工厂方法

  • 定义一个接口来创建对象,工厂本身并不创建对象,而交给子类完成,子类决定要实例化哪些类。
  • Factory方法的创建时通过继承而不是通过实例化。
  • 工厂方法更加具有可定制性,它可以返回相同的实例或者子类,而不是某种类型的对象。

假设每个页面都有一块区域显示个人信息,但是内容不同,设计代码如下:

from abc import ABCMeta, abstractmethod# 一个区表示哪方面内容,抽象的
class Section(metaclass=ABCMeta):@abstractmethoddef describe(self):pass# 接下来创建多个区域,用来分别显示不同的区域(简化只打印出来)
# 个人区
class PersonalSection(Section):def describe(self):print('personal section')# 音乐部分
class AlbumSection(Section):def describe(self):print('album')# 专利部分
class PatentSection(Section):def describe(self):print('patent')# 出版部分
class PublicationSection(Section):def describe(self):print('publication')# 接下来创建抽象类,提供工厂方法create_profile
class Profile(metaclass=ABCMeta):def __init__(self):self.sections = []self.create_profile()@abstractmethoddef create_profile(self):passdef get_sections(self):return self.sectionsdef add_sections(self, section):self.sections.append(section)# 接下来创建两个具体实现工厂方法的子类
class ConcreteCreator1(Profile):def create_profile(self):# 添加个人区域、专利区域、出版区域self.add_sections(PersonalSection())self.add_sections(PatentSection())self.add_sections(PublicationSection())class ConcreteCreator2(Profile):def create_profile(self):# 添加个人区域、音乐区域self.add_sections(PersonalSection())self.add_sections(AlbumSection())if __name__ == '__main__':# 要创建ConcreteCreator1这个对象profile_type = 'ConcreteCreator1'profile = eval(profile_type)()print(type(profile).__name__)print(profile.get_sections())'''结果ConcreteCreator1[<__main__.PersonalSection object at 0x10a052358>, <__main__.PatentSection object at 0x10a052390>, <__main__.PublicationSection object at 0x10a0523c8>]'''

工厂方法优点

  • 更好的灵活性,代码更通用,因为他不是单纯的实例某个类,而是取决于接口
  • 松耦合,创建对象的代码和使用它的代码是分开的,添加新类更容易。

抽象工厂

  • 抽象工厂主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类。
  • 相比于之前的需要我们去指定创建什么对象,抽象工厂不需要。

假设一个披萨店提供多种披萨,对应的抽象工厂:

'''抽象工厂:
1.抽象工厂主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类。
2.相比于之前的需要我们去指定创建什么对象,抽象工厂不需要。'''
from abc import ABCMeta, abstractmethodclass PizzaFactory(metaclass=ABCMeta):# 有蔬菜的披萨@abstractmethoddef create_veg_pizza(self):pass# 没蔬菜的披萨@abstractmethoddef create_non_veg_pizza(self):passclass USAPizzaFactory(PizzaFactory):# USA披萨店里有蔬菜的披萨是玉米披萨def create_veg_pizza(self):return CornPizza()# USA店里没蔬菜的披萨是牛肉披萨def create_non_veg_pizza(self):return BeefPizza()class ChinaPizzaFactory(PizzaFactory):# 中国披萨店里有蔬菜的披萨是水果披萨def create_veg_pizza(self):return FruitsPizza()# 中国披萨店里没有蔬菜的披萨是羊肉披萨def create_non_veg_pizza(self):return MuttonPizza()# 接下来定义4种披萨和他们的父类(有蔬菜和无蔬菜)
class VegPizza(metaclass=ABCMeta):@abstractmethoddef prepare(self, veg_pizza):pass# 没蔬菜的披萨在有蔬菜的披萨上面加肉就可以
class NonVegPizza(metaclass=ABCMeta):@abstractmethoddef serve(self, veg_pizza):passclass CornPizza(VegPizza):def prepare(self):print(type(self).__name__, '来了')class BeefPizza(NonVegPizza):def serve(self, veg_pizza):print(type(self).__name__, '来了,牛肉是加在', type(veg_pizza).__name__,'里面的')class FruitsPizza(VegPizza):def prepare(self):print(type(self).__name__, '来了')class MuttonPizza(NonVegPizza):def serve(self, veg_pizza):print(type(self).__name__, '来了,羊肉是加在', type(veg_pizza).__name__,'里面的')class PizzaStore(object):def __init__(self):passdef make_pizzas(self):# 创建的是所有对象(所有披萨),而不是单个指定对象for factory in [USAPizzaFactory(), ChinaPizzaFactory()]:self.factory = factoryself.non_veg_pizza = self.factory.create_non_veg_pizza()self.veg_pizza = self.factory.create_veg_pizza()# 调用self.veg_pizza.prepare()self.non_veg_pizza.serve(self.veg_pizza)pizza = PizzaStore()
pizza.make_pizzas()

工厂方法和抽象工厂的比较

工厂方法 抽象工厂
开放一个创建对象的方法 包含一个或多个工厂方法来创建一系列对象
使用继承和子类来决定创建什么对象 实用组合将创建对象的任务交给其他类
创建一个产品 创建相关系列(一群组)产品

Python实现简单工厂、工厂方法、抽象工厂设计模式相关推荐

  1. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂)

    园子里关于23种设计模式的博文已经可以说是成千上万.车载斗量.屯街塞巷.不计其数.数不胜数.摩肩接踵.汗牛充栋.车水马龙.门庭若市.琳琅满目直至让人眼花缭乱了.在这样的大环境下之所以来写设计模式类的博 ...

  2. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录

    1楼留头头大神:http://www.cnblogs.com/toutou/p/4899388.html v阅读目录 v写在前面 v简单工厂模式 v工厂方法模式 v抽象工厂模式 v博客总结 v博客前言 ...

  3. 简单工厂-工厂方法-抽象工厂

    目录 简单工厂 工厂方法 抽象工厂 前言 之前看书认真了解过这三种模式,但因为没有做记录,都给忘完了.现在重新分析网上的博客发现跟书里讲的不太一样,哎-.现在能做的就是把现在的理解给记录一下,若以后有 ...

  4. 简单工厂 工厂方法 抽象工厂 如何理解

    文章目录 前言 一.简单工厂 二.工厂方法 三.抽象工厂 总结 前言 简单工厂,工厂方法,抽象工厂,三者有什么区别? 搞清楚他们有什么弊端,以发展的角度去观察,理解会更加深入. 提示:以下是本篇文章正 ...

  5. java 三种工厂模式(简单工厂+工厂方法+抽象工厂)

    一.简单工厂模式 概述   简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的 实例,被创建的实例通常都具有共同的父类.因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因 ...

  6. 设计模式学习笔记——03 简单工厂 工厂方法 抽象工厂

    简单工厂 简单工厂模式也成静态工厂模式,但此模式不符合开闭原则,但仍然很常用 适用范围:工厂类需要创建的对象种类比较少,客户端只需要知道传入工厂类的参数,对于如何创建对象(逻辑)不关心 上段代码: p ...

  7. JAVA工厂模式优缺点_简单工厂模式、工厂模式和抽象工厂模式区别及优缺点

    各位小伙伴好,今天给大家主要介绍一下简单工厂模式.工厂模式和抽象工厂模式的区别及各自的优缺点. (本文实现语言为Python3) [前言] 众所周知今天所讲的内容是 设计模式的一类:对于设计模式这个概 ...

  8. 简单工厂模式、工厂模式和抽象工厂模式区别及优缺点

    各位小伙伴好,今天给大家主要介绍一下简单工厂模式.工厂模式和抽象工厂模式的区别及各自的优缺点. (本文实现语言为Python3) [前言] 众所周知今天所讲的内容是设计模式的一类:对于设计模式这个概念 ...

  9. GOLANG工厂模式、简单工厂模式、抽象工厂模式、创建者模式

    设计模式可以大大提高代码复用性,使得程序的修改更加灵活.另外将各个功能模块抽象解耦出来,在某个模块需要更改时不至于会对整体代码进行修改,解耦的好的话只简单修改几个地方即可以切换某个模块在实现上的切换, ...

  10. 【软件设计模式】工厂模式(简单工厂模式、一般工厂模式、抽象工厂模式)

    概述: 工厂模式把对象的创建交由某个特定的类来实现,该类为工厂类,该类的方法称为工厂方法,仅仅负责创建对象,从而将客户端复杂的对象创建语句实现解耦.责任分离,方便扩展和维护. 分类: 工厂模式分为简单 ...

最新文章

  1. [JS]正则式的使用示例:替换字符串中所有指定内容
  2. Vue源码终笔-VNode更新与diff算法初探
  3. Object-C 入门介绍
  4. 虚幻4皮肤材质_虚幻周报20200721 | CJ就要开始啦~
  5. Java程序员从笨鸟到菜鸟之(八十九)跟我学jquery(五)jquery中的ajax详解
  6. 阅读器xodo_佐道Xodo——手机最佳pdf阅读器
  7. Wait waitpid
  8. 语言速算24点的小窍门_4秒钟1道题!12岁少年三夺24点大赛冠军
  9. ORACLE异常(整理网上资料)
  10. sql08 访问接口没有oraoledb_如何配置交换机和防火墙以访问 Internet?
  11. C# 计算程序运行耗时的方法
  12. 计算机408考研 思维导图 知识整理
  13. 自制纯正弦波 12V转220V 1000瓦逆变器做家用太阳能电源
  14. 相位测试音频mp3_音频测试标准是什么?
  15. bgfx入门练习2——找出DX,OpenGL驱动切换实现原理
  16. 双显卡(Intel+Nvidia)笔记本配置cuda开发环境
  17. WPA3功能开发及验证
  18. Django Swagger文档库drf-spectacular
  19. windows下的host文件在哪里,有什么作用?
  20. 主机地址、网络地址、主机路由、网络路由

热门文章

  1. cephadm搭建ceph集群
  2. 暴雪服务器是linux吗,暴雪内部就这么玩:Linux运行《魔兽世界》教程
  3. TDDL(taobao distributed data layer )作数据路由层
  4. java实现镜像系统_谷歌开源Java镜像构建工具Jib
  5. 在 Android 模拟器上设置 Sencha Touch
  6. Django开发常用方法及面试题
  7. Linux 常用命令与教程
  8. 【无标题】upc放鞭炮13855
  9. 【self-instruct方式生成语料代码实战】
  10. 自己 编译 linux 内核,自己动手编译Linux内核