單例模式sql
所謂單例模式,也就是說無論何時咱們要確保只有一個對象實例存在。不少狀況下,整個系統中只須要存在一個對象,全部的信息都從這個對象獲取,好比系統的配置對象,或者是線程池。這些場景下,就很是適合使用單例模式。總結起來,就是說無論咱們初始化一個對象多少次,真正幹活的對象只會生成一次而且在首次生成。數據庫
咱們可使用單例模式來保證鏈接數據庫只會發生一次。下面咱們看看一個簡單的 Flask Web 框架的 sqlite 擴展。flask
import sqlite3
from flask import current_app
from flask import _app_ctx_stack as stackapp
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了。dom
能夠看到單例模式的實現只須要找一個變量存放建立的實例,而後每次獲取實例時,先檢查變量中是否已保存實例,若是沒有則建立一個實例並將其存放到變量中,之後都從這個變量中獲取實例就能夠了。單例模式中,只會建立一次實例。線程
工廠模式code
「工廠」兩字,一目瞭然。所謂工廠模式,也就是說咱們能夠經過工廠類建立產品。sqlite
在工廠方法模式中,咱們會遇到一個問題,當產品很是多時,繼續使用工廠方法模式會產生很是多的工廠類。對象
如今咱們有一個產品是課程,可是僅僅依靠課程還沒辦法提供完美的服務,由於在 實驗樓 你能夠邊學課程邊作實驗呢。在哪裏作實驗呢?固然是在虛擬機裏了。固然咱們也有不少種虛擬機,好比 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())
抽象工廠模式順利的解決了工廠方法模式中遇到的問題,咱們經過將產品的建立進行組合放入一個工廠類中,不但減小了工廠類的數量,還增長了生產產品體系的能力(好比課程和虛擬機組成了一個產品體系)實驗樓。如今,工廠類不單單能建立課程,還能建立虛擬機,咱們只須要一座工廠就能爲 實驗樓 用戶服務啦 。
從簡單工廠模式到抽象工廠模式,咱們都是在用後一種模式解決前一種模式的缺陷,都是在最大程度下降代碼的耦合性。在使用工廠模式家族時,無論使用哪種工廠模式,只要能達到最大程度的解耦,都是不錯的選擇。