资讯专栏INFORMATION COLUMN

python之单例模式和工厂模式

jayce / 2332人阅读

摘要:在工厂方法模式中,我们会遇到一个问题,当产品非常多时,继续使用工厂方法模式会产生非常多的工厂类。从简单工厂模式到抽象工厂模式,我们都是在用后一种模式解决前一种模式的缺陷,都是在最大程度降低代码的耦合性。

单例模式

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

我们可以使用单例模式来保证连接数据库只会发生一次。下面我们看看一个简单的 Flask Web 框架的 sqlite 扩展。

-- 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

在以上的代码中,我们每次使用数据库的时候通过 SQLite3.connection 获取数据库连接就可以了。SQLite3.connection保证了数据库连接只会发生一次,其原理和之前我们实现单例模式的方式相同,只不过这里存储实例的地方变成 flask._app_ctx_stack了。

可以看到单例模式的实现只需要找一个变量存放创建的实例,然后每次获取实例时,先检查变量中是否已保存实例,如果没有则创建一个实例并将其存放到变量中,以后都从这个变量中获取实例就可以了。单例模式中,只会创建一次实例。

工厂模式

“工厂”两字,一目了然。所谓工厂模式,也就是说我们可以通过工厂类创建产品。

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

现在我们有一个产品是课程,但是仅仅依靠课程还没办法提供完美的服务,因为在 实验楼 你可以边学课程边做实验呢。在哪里做实验呢?当然是在虚拟机里了。当然我们也有很多种虚拟机,比如 Linux 虚拟机和 Mac 虚拟机。

如果按照工厂方法模式的作法,我们需要创建 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())

抽象工厂模式顺利的解决了工厂方法模式中遇到的问题,我们通过将产品的创建进行组合放入一个工厂类中,不但减少了工厂类的数量,还增加了生产产品体系的能力(比如课程和虚拟机组成了一个产品体系)实验楼。现在,工厂类不仅仅能创建课程,还能创建虚拟机,我们只需要一座工厂就能为 实验楼 用户服务啦 。

从简单工厂模式到抽象工厂模式,我们都是在用后一种模式解决前一种模式的缺陷,都是在最大程度降低代码的耦合性。在使用工厂模式家族时,不管使用哪一种工厂模式,只要能达到最大程度的解耦,都是不错的选择。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/44121.html

相关文章

  • 优才公开课笔记:php设计模式(一) 单例模式

    摘要:最近开展了三次设计模式的公开课,现在来总结一下设计模式在中的应用,这是第一篇创建型模式之单例模式。不过因为不支持多线程所以不需要考虑这个问题了。 最近开展了三次设计模式的公开课,现在来总结一下设计模式在PHP中的应用,这是第一篇创建型模式之单例模式。 一、设计模式简介 首先我们来认识一下什么是设计模式: 设计模式是一套被反复使用、容易被他人理解的、可靠的代码设计经验的总结。 设计模式不...

    guyan0319 评论0 收藏0
  • Java基础学习——多线程单例设计模式(转)

    摘要:总之,选择单例模式就是为了避免不一致状态,避免政出多头。二饿汉式单例饿汉式单例类在类初始化时,已经自行实例化静态工厂方法饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。 概念:  Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿汉式单例。  单例模式有以下特点:  1、单例类只能有一个实例。 ...

    dendoink 评论0 收藏0
  • 每天一个设计模式单例模式

    摘要:博主按每天一个设计模式旨在初步领会设计模式的精髓,目前采用靠这吃饭和纯粹喜欢两种语言实现。单例模式用途如果一个类负责连接数据库的线程池日志记录逻辑等等,此时需要单例模式来保证对象不被重复创建,以达到降低开销的目的。 博主按:《每天一个设计模式》旨在初步领会设计模式的精髓,目前采用javascript(_靠这吃饭_)和python(_纯粹喜欢_)两种语言实现。诚然,每种设计模式都有多种实...

    yy736044583 评论0 收藏0
  • 每天一个设计模式单例模式

    摘要:博主按每天一个设计模式旨在初步领会设计模式的精髓,目前采用靠这吃饭和纯粹喜欢两种语言实现。单例模式用途如果一个类负责连接数据库的线程池日志记录逻辑等等,此时需要单例模式来保证对象不被重复创建,以达到降低开销的目的。 博主按:《每天一个设计模式》旨在初步领会设计模式的精髓,目前采用javascript(_靠这吃饭_)和python(_纯粹喜欢_)两种语言实现。诚然,每种设计模式都有多种实...

    lijy91 评论0 收藏0
  • python单例模式实现的三种方式

    摘要:输出结果输出结果此外还有两种实现单例的方式,我呢也给大家列出来,方便大家学习和参考方式一方式二单例模式实现方式二。。。 什么是单例模式?通俗点讲:单例模式就是在程序执行的过程中,类只有一个实例,这不是说单例模式只能去创建一个实例,而是你创建的所有实例(也就是对象)都指的是同一个实例。如何做到这一点呢?我们的__new__特殊方法就派上用场了,可能大家对这个方法熟悉又陌生,那么接下来通过...

    dack 评论0 收藏0

发表评论

0条评论

jayce

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<