如何将Python中的单例模式和工厂模式家族改写为一种长尾?

2026-04-11 08:251阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1892个文字,预计阅读时间需要8分钟。

如何将Python中的单例模式和工厂模式家族改写为一种长尾?

Python设计模式-创建型模式:单例模式家族+知识点:单例模式概念及一般实现+单例模式的装饰器实现+简单工厂模式+抽象工厂模式+单例模式(singleton)所谓单例模式,也就是……

Python设计模式-创建型:单例模式和工厂模式家族

知识点

  • 单例模式概念及一般实现
  • 单例模式的装饰器实现
  • 简单工厂模式
  • 抽象工厂模式
单例模式(singleton)
  • 所谓单例模式,也就是说不管什么时候我们要确保只有一个对象实例存在。
  • 很多情况下,整个系统中只需要存在一个对象,所有的信息都从这个对象获取,比如系统的配置对象,或者是线程池。
  • 这些场景下,就非常适合使用单例模式。总结起来,就是说不管我们初始化一个对象多少次,真正干活的对象只会生成一次并且在首次生成。
Singleton._instance

# -*- coding: utf-8 -*- class Singleton(object): """ 单例模式 """ class _A(object): """ 真正干活的类, 对外隐藏 """ def __init__(self): pass def display(self): """ 返回当前实例的 ID,是全局唯一的""" return id(self) # 类变量,用于存储 _A 的实例 _instance = None def __init__(self): """ 先判断类变量中是否已经保存了 _A 的实例,如果没有则创建一个后返回""" if Singleton._instance is None: Singleton._instance = Singleton._A() def __getattr__(self, attr): """ 所有的属性都应该直接从 Singleton._instance 获取""" return getattr(self._instance, attr) if __name__ == '__main__': # 创建两个实例 s1 = Singleton() s2 = Singleton() print(id(s1), s1.display()) print(id(s2), s2.display())

  • 使用类变量 Singleton._instance 来存储创建的实例,并且保证只会创建一次实例。

  • 由于 Python 是一门动态语言,我们可以在运行时改变类定义。

  • 在首次初始化Singleton时,我们将首次生成类_A的实例,并将其存储到 Singleton._instance 中,以后每次初始化 Singleton 时都从 Singleton._instance 获取真正干活的实例,这样我们就实现了单例模式。

    如何将Python中的单例模式和工厂模式家族改写为一种长尾?

装饰器

# -*- coding: utf-8 -*- class Singleton: """ 单例类装饰器,可以用于想实现单例的任何类。注意,不能用于多线程环境。 """ def __init__(self, cls): """ 需要的参数是一个类 """ self._cls = cls def Instance(self): """ 返回真正的实例 """ try: return self._instance except AttributeError: self._instance = self._cls() return self._instance def __call__(self): raise TypeError('Singletons must be accessed through `Instance()`.') def __instancecheck__(self, inst): return isinstance(inst, self._decorated) # 装饰器 @Singleton class A: """一个需要单例模式的类""" def __init__(self): pass def display(self): return id(self) if __name__ == '__main__': s1 = A.Instance() s2 = A.Instance() print(s1, s1.display()) print(s2, s2.display()) print(s1 is s2)

  • 用装饰器实现了单例模式,任何想使用单例模式的类,只需要使用 Singleton 装饰器装饰一下就可以使用了。
  • 可以看到其核心工作原理其实和第一种实现方式是一致的,也是使用内置的属性 Singleton._instance 来存储实例的。通过使用装饰器的模式我们将代码解耦了,使用更加灵活
案例-单例模式-连接sqlite3数据库

# -*- coding: utf-8 -*- import sqlite3 from flask import current_app from flask import _app_ctx_stack as stack class SQLite3(object): def __init__(self, app=None): self.app = app if app is not None: self.init_app(app) def init_app(self, app): """ 典型的 Flask 扩展的初始化方式 """ app.config.setdefault('SQLITE3_DATABASE', ':memory:') app.teardown_appcontext(self.teardown) def connect(self): """ 连接到 sqlite 数据库 """ return sqlite3.connect(current_app.config['SQLITE3_DATABASE']) def teardown(self, exception): """ 关闭 sqlite 链接 """ ctx = stack.top if hasattr(ctx, 'sqlite3_db'): ctx.sqlite3_db.close() @property def connection(self): """ 单例模式在这里:使用 flask._app_ctx_stack 存放 sqlite 链接, 每次获取数据库链接时都通过 connection 获取 """ ctx = stack.top if ctx is not None: if not hasattr(ctx, 'sqlite3_db'): ctx.sqlite3_db = self.connect() return ctx.sqlite3_db 简单工厂模式 Simple factory

一个函数,传入需要创建的产品类型,然后返回相应的产品

# -*- coding: utf-8 -*- import random class BasicCourse(object): """ 基础课程 """ def get_labs(self): return "basic_course: labs" def __str__(self): return "BasciCourse" class ProjectCourse(object): """ 项目课 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse" class SimpleCourseFactory(object): @staticmethod def create_course(type): """ 简单工厂,用于创建课程""" if type == 'bc': return BasicCourse() elif type == 'pc': return ProjectCourse() if __name__ == '__main__': t = random.choice(['bc', 'pc']) course = SimpleCourseFactory.create_course(t) print(course.get_labs()) 工厂方法模式 factory method

上面的简单工厂模式中,我们遇到了问题:如果需要增加一种课程,那我们需要修改工厂代码。仔细想想,如果对工厂进行抽象化,让每个工厂只负责一种产品的生产,那这样当增加一种产品时,就不需要修改已有的工厂了,只需要新增加一个工厂就行了,这样就避免修改整个工厂了

# -*- coding: utf-8 -*- import random import abc class BasicCourse(object): """ 基础课程 """ def get_labs(self): return "basic_course: labs" def __str__(self): return "BasicCourse" class ProjectCourse(object): """ 项目课 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse" class Factory(metaclass=abc.ABCMeta): """ 抽象工厂类 """ @abc.abstractmethod def create_course(self): pass class BasicCourseFactory(Factory): """ 基础课程工厂类 """ def create_course(self): return BasicCourse() class ProjectCourseFactory(Factory): """ 项目课程工厂类 """ def create_course(self): return ProjectCourse() def get_factory(): """ 随机获取一个工厂类 """ return random.choice([BasicCourseFactory, ProjectCourseFactory])() if __name__ == '__main__': factory = get_factory() course = factory.create_course() print(course.get_labs())

我们有两种课程:BasicCourse 和 ProjectCourse,分别对应基础课和项目课。接着,我们创建了一个抽象的工厂 Factory,该工厂有一抽象方法Factory.create_course用于创建课程,最后我们基于抽象工厂实现了生产基础课程的工厂BasicCourseFactory和生产项目课的工厂ProjectCourseFactory。这样当我们新增加一种课程时,就不需要修改已经存在的基础课工厂和项目课工厂了。这里需要说明下,我们通过 Python 的abc模块实现抽象类和抽象方法。

抽象工厂模式

在工厂方法模式中,我们会遇到一个问题,当产品非常多时,继续使用工厂方法模式会产生非常多的工厂类。

如果按照工厂方法模式的作法,我们需要创建 Linux 虚拟机工厂类和 Mac 虚拟机工厂类, 这样我们就会有一堆工厂类了。我们就不能创建出一个能同时创建课程和虚拟机的工厂吗?

-*- coding: utf-8 -*- import random import abc # 两种类型的课程 class BasicCourse(object): """ 基础课程 """ def get_labs(self): return "basic_course: labs" def __str__(self): return "BasicCourse" class ProjectCourse(object): """ 项目课 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse" # 两种类型的虚拟机 class LinuxVm(object): """ Linux 虚拟机 """ def start(self): return "Linux vm running" class MacVm(object): """ Mac OSX 虚拟机 """ def start(self): return "Mac OSX vm running" class Factory(metaclass=abc.ABCMeta): """ 抽象工厂类, 现在工厂类不仅能创建课程,还能创建虚拟机了 """ @abc.abstractmethod def create_course(self): pass @abc.abstractmethod def create_vm(self): pass class BasicCourseLinuxFactory(Factory): """ 基础课程工厂类 """ def create_course(self): return BasicCourse() def create_vm(self): return LinuxVm() class ProjectCourseMacFactory(Factory): """ 项目课程工厂类 """ def create_course(self): return ProjectCourse() def create_vm(self): return MacVm() def get_factory(): """ 随机获取一个工厂类 """ return random.choice([BasicCourseLinuxFactory, ProjectCourseMacFactory])() if __name__ == '__main__': factory = get_factory() course = factory.create_course() vm = factory.create_vm() print(course.get_labs()) print(vm.start())

本文共计1892个文字,预计阅读时间需要8分钟。

如何将Python中的单例模式和工厂模式家族改写为一种长尾?

Python设计模式-创建型模式:单例模式家族+知识点:单例模式概念及一般实现+单例模式的装饰器实现+简单工厂模式+抽象工厂模式+单例模式(singleton)所谓单例模式,也就是……

Python设计模式-创建型:单例模式和工厂模式家族

知识点

  • 单例模式概念及一般实现
  • 单例模式的装饰器实现
  • 简单工厂模式
  • 抽象工厂模式
单例模式(singleton)
  • 所谓单例模式,也就是说不管什么时候我们要确保只有一个对象实例存在。
  • 很多情况下,整个系统中只需要存在一个对象,所有的信息都从这个对象获取,比如系统的配置对象,或者是线程池。
  • 这些场景下,就非常适合使用单例模式。总结起来,就是说不管我们初始化一个对象多少次,真正干活的对象只会生成一次并且在首次生成。
Singleton._instance

# -*- coding: utf-8 -*- class Singleton(object): """ 单例模式 """ class _A(object): """ 真正干活的类, 对外隐藏 """ def __init__(self): pass def display(self): """ 返回当前实例的 ID,是全局唯一的""" return id(self) # 类变量,用于存储 _A 的实例 _instance = None def __init__(self): """ 先判断类变量中是否已经保存了 _A 的实例,如果没有则创建一个后返回""" if Singleton._instance is None: Singleton._instance = Singleton._A() def __getattr__(self, attr): """ 所有的属性都应该直接从 Singleton._instance 获取""" return getattr(self._instance, attr) if __name__ == '__main__': # 创建两个实例 s1 = Singleton() s2 = Singleton() print(id(s1), s1.display()) print(id(s2), s2.display())

  • 使用类变量 Singleton._instance 来存储创建的实例,并且保证只会创建一次实例。

  • 由于 Python 是一门动态语言,我们可以在运行时改变类定义。

  • 在首次初始化Singleton时,我们将首次生成类_A的实例,并将其存储到 Singleton._instance 中,以后每次初始化 Singleton 时都从 Singleton._instance 获取真正干活的实例,这样我们就实现了单例模式。

    如何将Python中的单例模式和工厂模式家族改写为一种长尾?

装饰器

# -*- coding: utf-8 -*- class Singleton: """ 单例类装饰器,可以用于想实现单例的任何类。注意,不能用于多线程环境。 """ def __init__(self, cls): """ 需要的参数是一个类 """ self._cls = cls def Instance(self): """ 返回真正的实例 """ try: return self._instance except AttributeError: self._instance = self._cls() return self._instance def __call__(self): raise TypeError('Singletons must be accessed through `Instance()`.') def __instancecheck__(self, inst): return isinstance(inst, self._decorated) # 装饰器 @Singleton class A: """一个需要单例模式的类""" def __init__(self): pass def display(self): return id(self) if __name__ == '__main__': s1 = A.Instance() s2 = A.Instance() print(s1, s1.display()) print(s2, s2.display()) print(s1 is s2)

  • 用装饰器实现了单例模式,任何想使用单例模式的类,只需要使用 Singleton 装饰器装饰一下就可以使用了。
  • 可以看到其核心工作原理其实和第一种实现方式是一致的,也是使用内置的属性 Singleton._instance 来存储实例的。通过使用装饰器的模式我们将代码解耦了,使用更加灵活
案例-单例模式-连接sqlite3数据库

# -*- coding: utf-8 -*- import sqlite3 from flask import current_app from flask import _app_ctx_stack as stack class SQLite3(object): def __init__(self, app=None): self.app = app if app is not None: self.init_app(app) def init_app(self, app): """ 典型的 Flask 扩展的初始化方式 """ app.config.setdefault('SQLITE3_DATABASE', ':memory:') app.teardown_appcontext(self.teardown) def connect(self): """ 连接到 sqlite 数据库 """ return sqlite3.connect(current_app.config['SQLITE3_DATABASE']) def teardown(self, exception): """ 关闭 sqlite 链接 """ ctx = stack.top if hasattr(ctx, 'sqlite3_db'): ctx.sqlite3_db.close() @property def connection(self): """ 单例模式在这里:使用 flask._app_ctx_stack 存放 sqlite 链接, 每次获取数据库链接时都通过 connection 获取 """ ctx = stack.top if ctx is not None: if not hasattr(ctx, 'sqlite3_db'): ctx.sqlite3_db = self.connect() return ctx.sqlite3_db 简单工厂模式 Simple factory

一个函数,传入需要创建的产品类型,然后返回相应的产品

# -*- coding: utf-8 -*- import random class BasicCourse(object): """ 基础课程 """ def get_labs(self): return "basic_course: labs" def __str__(self): return "BasciCourse" class ProjectCourse(object): """ 项目课 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse" class SimpleCourseFactory(object): @staticmethod def create_course(type): """ 简单工厂,用于创建课程""" if type == 'bc': return BasicCourse() elif type == 'pc': return ProjectCourse() if __name__ == '__main__': t = random.choice(['bc', 'pc']) course = SimpleCourseFactory.create_course(t) print(course.get_labs()) 工厂方法模式 factory method

上面的简单工厂模式中,我们遇到了问题:如果需要增加一种课程,那我们需要修改工厂代码。仔细想想,如果对工厂进行抽象化,让每个工厂只负责一种产品的生产,那这样当增加一种产品时,就不需要修改已有的工厂了,只需要新增加一个工厂就行了,这样就避免修改整个工厂了

# -*- coding: utf-8 -*- import random import abc class BasicCourse(object): """ 基础课程 """ def get_labs(self): return "basic_course: labs" def __str__(self): return "BasicCourse" class ProjectCourse(object): """ 项目课 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse" class Factory(metaclass=abc.ABCMeta): """ 抽象工厂类 """ @abc.abstractmethod def create_course(self): pass class BasicCourseFactory(Factory): """ 基础课程工厂类 """ def create_course(self): return BasicCourse() class ProjectCourseFactory(Factory): """ 项目课程工厂类 """ def create_course(self): return ProjectCourse() def get_factory(): """ 随机获取一个工厂类 """ return random.choice([BasicCourseFactory, ProjectCourseFactory])() if __name__ == '__main__': factory = get_factory() course = factory.create_course() print(course.get_labs())

我们有两种课程:BasicCourse 和 ProjectCourse,分别对应基础课和项目课。接着,我们创建了一个抽象的工厂 Factory,该工厂有一抽象方法Factory.create_course用于创建课程,最后我们基于抽象工厂实现了生产基础课程的工厂BasicCourseFactory和生产项目课的工厂ProjectCourseFactory。这样当我们新增加一种课程时,就不需要修改已经存在的基础课工厂和项目课工厂了。这里需要说明下,我们通过 Python 的abc模块实现抽象类和抽象方法。

抽象工厂模式

在工厂方法模式中,我们会遇到一个问题,当产品非常多时,继续使用工厂方法模式会产生非常多的工厂类。

如果按照工厂方法模式的作法,我们需要创建 Linux 虚拟机工厂类和 Mac 虚拟机工厂类, 这样我们就会有一堆工厂类了。我们就不能创建出一个能同时创建课程和虚拟机的工厂吗?

-*- coding: utf-8 -*- import random import abc # 两种类型的课程 class BasicCourse(object): """ 基础课程 """ def get_labs(self): return "basic_course: labs" def __str__(self): return "BasicCourse" class ProjectCourse(object): """ 项目课 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse" # 两种类型的虚拟机 class LinuxVm(object): """ Linux 虚拟机 """ def start(self): return "Linux vm running" class MacVm(object): """ Mac OSX 虚拟机 """ def start(self): return "Mac OSX vm running" class Factory(metaclass=abc.ABCMeta): """ 抽象工厂类, 现在工厂类不仅能创建课程,还能创建虚拟机了 """ @abc.abstractmethod def create_course(self): pass @abc.abstractmethod def create_vm(self): pass class BasicCourseLinuxFactory(Factory): """ 基础课程工厂类 """ def create_course(self): return BasicCourse() def create_vm(self): return LinuxVm() class ProjectCourseMacFactory(Factory): """ 项目课程工厂类 """ def create_course(self): return ProjectCourse() def create_vm(self): return MacVm() def get_factory(): """ 随机获取一个工厂类 """ return random.choice([BasicCourseLinuxFactory, ProjectCourseMacFactory])() if __name__ == '__main__': factory = get_factory() course = factory.create_course() vm = factory.create_vm() print(course.get_labs()) print(vm.start())