python之单例模式和工厂模式

AlgoVoyantX
• 阅读 3373

单例模式

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

我们可以使用单例模式来保证连接数据库只会发生一次。下面我们看看一个简单的 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())

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

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

点赞
收藏
评论区
推荐文章
3A网络 3A网络
2年前
Golang 常见设计模式之单例模式
之前我们已经看过了Golang常见设计模式中的装饰和选项模式,今天要看的是Golang设计模式里最简单的单例模式。单例模式的作用是确保无论对象被实例化多少次,全局都只有一个实例存在。根据这一特性,我们可以将其应用到全局唯一性配置、数据库连接对象、文件访问对象等。Go语言实现单例模式的方法有很多种,下面我们就一起来看一下。饿汉式饿汉式实现单例模式非
Wesley13 Wesley13
3年前
java设计模式1
1:单例模式简介  单例模式是一种常用的软件设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供唯一的实例。总而言之就是在系统中只会存在一个对象,其中的数据是共享的  特点:    单例类只能有一个实例,所以一般会用static进行修释。    单例类必须自己创建自己的唯一实例。也就是在类中要new一个自己。    单例类必
Wesley13 Wesley13
3年前
java 23种设计模式(五、单例模式)
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。单例模式的结构  单例模式的特点:单例类只能有一个实例。单例类必须自己创建自己的唯一实例。单例类必须给所有其他对象提供这一实例。  饿汉式单例类publicclassEagerSingleton
Wesley13 Wesley13
3年前
java中单例模式的比较
单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好、用对单例模式,还真得费一番脑筋。本文对Java中常见的单例模式写法做了一个总结,如有错漏之处,恳请读者指正。饿汉法:就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。public class Singleton {           pr
红烧土豆泥 红烧土豆泥
4年前
创建型模式之单例设计模式
什么是单例设计模式?顾名思义,只有一个实例。单例模式它主要是确保一个类只有一个实例,并且可以提供一个全局的访问点。废话少说,直接上干货了单例模式之饿汉式所谓饿汉式,顾名思义,“它很饿”。所以说,它一旦被加载进来,就会直接实例化一个对象。例如:languageclassSingleton{privatestaticfin
Wesley13 Wesley13
3年前
JAVA设计模式之单例设计模式
    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。  在JAVA中实现单例,必须了解JAVA内存机制,JAVA中实例对象存在于堆内存中,若要实现单例,必须满足两个条件:  1.限制类实例化对象。即只能产生一个对象。
Wesley13 Wesley13
3年前
Java单例模式
什么是单例模式  单例模式是在程序中,一个类保证只有一个实例,并提供统一的访问入口。为什么要用单例模式节省内存节省计算如对象实例中的一样的,那就不用每次都创建一个对象方便管理因为单例提供一个统一的访问入口,不需要创建N多个对象,很多工具类都用了单例实现,如日志、字符串工具类
Wesley13 Wesley13
3年前
PHP单例模式(精讲)
首先我们要明确单例模式这个概念,那么什么是单例模式呢?单例模式顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类我们称之为单例类。单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例
Stella981 Stella981
3年前
C#设计模式(1)——单例模式(Singleton)
单例模式即所谓的一个类只能有一个实例,也就是类只能在内部实例一次,然后提供这一实例,外部无法对此类实例化。单例模式的特点:1、只能有一个实例;2、只能自己创建自己的唯一实例;3、必须给所有其他的对象提供这一实例。普通单例模式(没有考虑线程安全)  ///<summary///单例模式
Wesley13 Wesley13
3年前
(面试常问)4种单例设计模式的总结(内含代码以及分析)
单例设计模式:  单例模式,是一种常见的软件设计模式.在它的核心结构中只包含了一个被称为单例的特殊类.通过单例模式可以保证系统中只有该类的一个实例对象.优点:  实例控制:单例模式会阻止其它对象实例化其自己的单例对象的副本,从而确保所有对象都访问的是唯一的实例   灵活性:因为类控制了实例化过程,所以类可以很灵活的更改实
Wesley13 Wesley13
3年前
23种设计模式(面向对象语言)
一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。创建型模式是用来创建对象的模式,抽象了实例化的过程,帮助一个系统独立于其他关联对象的创建、组合和表示方式。所有的创建型模式都有两个主要功能:  1.将系统所使用的具体类的信息封装起来  2.隐藏
AlgoVoyantX
AlgoVoyantX
Lv1
思归若汾水,无日不悠悠。
文章
1
粉丝
0
获赞
0
热门文章

暂无数据