摘要:在工廠方法模式中,我們會遇到一個問題,當產(chǎn)品非常多時,繼續(xù)使用工廠方法模式會產(chǎn)生非常多的工廠類。從簡單工廠模式到抽象工廠模式,我們都是在用后一種模式解決前一種模式的缺陷,都是在最大程度降低代碼的耦合性。
單例模式
所謂單例模式,也就是說不管什么時候我們要確保只有一個對象實例存在。很多情況下,整個系統(tǒng)中只需要存在一個對象,所有的信息都從這個對象獲取,比如系統(tǒng)的配置對象,或者是線程池。這些場景下,就非常適合使用單例模式。總結(jié)起來,就是說不管我們初始化一個對象多少次,真正干活的對象只會生成一次并且在首次生成。
我們可以使用單例模式來保證連接數(shù)據(jù)庫只會發(fā)生一次。下面我們看看一個簡單的 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 數(shù)據(jù)庫 """ return sqlite3.connect(current_app.config["SQLITE3_DATABASE"]) def teardown(self, exception): """ 關(guān)閉 sqlite 鏈接 """ ctx = stack.top if hasattr(ctx, "sqlite3_db"): ctx.sqlite3_db.close() @property def connection(self): """ 單例模式在這里:使用 flask._app_ctx_stack 存放 sqlite 鏈接, 每次獲取數(shù)據(jù)庫鏈接時都通過 connection 獲取 """ ctx = stack.top if ctx is not None: if not hasattr(ctx, "sqlite3_db"): ctx.sqlite3_db = self.connect() return ctx.sqlite3_db
在以上的代碼中,我們每次使用數(shù)據(jù)庫的時候通過 SQLite3.connection 獲取數(shù)據(jù)庫連接就可以了。SQLite3.connection保證了數(shù)據(jù)庫連接只會發(fā)生一次,其原理和之前我們實現(xiàn)單例模式的方式相同,只不過這里存儲實例的地方變成 flask._app_ctx_stack了。
可以看到單例模式的實現(xiàn)只需要找一個變量存放創(chuàng)建的實例,然后每次獲取實例時,先檢查變量中是否已保存實例,如果沒有則創(chuàng)建一個實例并將其存放到變量中,以后都從這個變量中獲取實例就可以了。單例模式中,只會創(chuàng)建一次實例。
工廠模式
“工廠”兩字,一目了然。所謂工廠模式,也就是說我們可以通過工廠類創(chuàng)建產(chǎn)品。
在工廠方法模式中,我們會遇到一個問題,當產(chǎn)品非常多時,繼續(xù)使用工廠方法模式會產(chǎn)生非常多的工廠類。
現(xiàn)在我們有一個產(chǎn)品是課程,但是僅僅依靠課程還沒辦法提供完美的服務(wù),因為在 實驗樓 你可以邊學課程邊做實驗?zāi)?。在哪里做實驗?zāi)兀慨斎皇窃谔摂M機里了。當然我們也有很多種虛擬機,比如 Linux 虛擬機和 Mac 虛擬機。
如果按照工廠方法模式的作法,我們需要創(chuàng)建 Linux 虛擬機工廠類和 Mac 虛擬機工廠類, 這樣我們就會有一堆工廠類了。但是在 實驗樓 里,真正的情況是只有虛擬機和課程結(jié)合在一起才能給用戶提供完美的服務(wù)。我們就不能創(chuàng)建出一個能同時創(chuàng)建課程和虛擬機的工廠嗎?因為我們知道其實用戶的需求同時包含了課程和虛擬機,如果有一座工廠能同時生產(chǎn)這兩種產(chǎn)品就完美了。
-- coding: utf-8 --
import random
import abc
class BasicCourse(object):
""" 基礎(chǔ)課程 """ 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):
""" 抽象工廠類, 現(xiàn)在工廠類不僅能創(chuàng)建課程,還能創(chuàng)建虛擬機了 """ @abc.abstractmethod def create_course(self): pass @abc.abstractmethod def create_vm(self): pass
class BasicCourseLinuxFactory(Factory):
""" 基礎(chǔ)課程工廠類 """ 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())
抽象工廠模式順利的解決了工廠方法模式中遇到的問題,我們通過將產(chǎn)品的創(chuàng)建進行組合放入一個工廠類中,不但減少了工廠類的數(shù)量,還增加了生產(chǎn)產(chǎn)品體系的能力(比如課程和虛擬機組成了一個產(chǎn)品體系)實驗樓?,F(xiàn)在,工廠類不僅僅能創(chuàng)建課程,還能創(chuàng)建虛擬機,我們只需要一座工廠就能為 實驗樓 用戶服務(wù)啦 。
從簡單工廠模式到抽象工廠模式,我們都是在用后一種模式解決前一種模式的缺陷,都是在最大程度降低代碼的耦合性。在使用工廠模式家族時,不管使用哪一種工廠模式,只要能達到最大程度的解耦,都是不錯的選擇。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/44121.html
摘要:最近開展了三次設(shè)計模式的公開課,現(xiàn)在來總結(jié)一下設(shè)計模式在中的應(yīng)用,這是第一篇創(chuàng)建型模式之單例模式。不過因為不支持多線程所以不需要考慮這個問題了。 最近開展了三次設(shè)計模式的公開課,現(xiàn)在來總結(jié)一下設(shè)計模式在PHP中的應(yīng)用,這是第一篇創(chuàng)建型模式之單例模式。 一、設(shè)計模式簡介 首先我們來認識一下什么是設(shè)計模式: 設(shè)計模式是一套被反復(fù)使用、容易被他人理解的、可靠的代碼設(shè)計經(jīng)驗的總結(jié)。 設(shè)計模式不...
摘要:總之,選擇單例模式就是為了避免不一致狀態(tài),避免政出多頭。二餓漢式單例餓漢式單例類在類初始化時,已經(jīng)自行實例化靜態(tài)工廠方法餓漢式在類創(chuàng)建的同時就已經(jīng)創(chuàng)建好一個靜態(tài)的對象供系統(tǒng)使用,以后不再改變,所以天生是線程安全的。 概念: Java中單例模式是一種常見的設(shè)計模式,單例模式的寫法有好幾種,這里主要介紹兩種:懶漢式單例、餓漢式單例?! 卫J接幸韵绿攸c: 1、單例類只能有一個實例?!?..
摘要:博主按每天一個設(shè)計模式旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語言實現(xiàn)。單例模式用途如果一個類負責連接數(shù)據(jù)庫的線程池日志記錄邏輯等等,此時需要單例模式來保證對象不被重復(fù)創(chuàng)建,以達到降低開銷的目的。 博主按:《每天一個設(shè)計模式》旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實...
摘要:博主按每天一個設(shè)計模式旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語言實現(xiàn)。單例模式用途如果一個類負責連接數(shù)據(jù)庫的線程池日志記錄邏輯等等,此時需要單例模式來保證對象不被重復(fù)創(chuàng)建,以達到降低開銷的目的。 博主按:《每天一個設(shè)計模式》旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實...
摘要:輸出結(jié)果輸出結(jié)果此外還有兩種實現(xiàn)單例的方式,我呢也給大家列出來,方便大家學習和參考方式一方式二單例模式實現(xiàn)方式二。。。 什么是單例模式?通俗點講:單例模式就是在程序執(zhí)行的過程中,類只有一個實例,這不是說單例模式只能去創(chuàng)建一個實例,而是你創(chuàng)建的所有實例(也就是對象)都指的是同一個實例。如何做到這一點呢?我們的__new__特殊方法就派上用場了,可能大家對這個方法熟悉又陌生,那么接下來通過...
閱讀 3268·2021-10-27 14:20
閱讀 2536·2021-10-08 10:05
閱讀 1635·2021-09-09 09:33
閱讀 2908·2019-08-30 13:16
閱讀 1445·2019-08-29 18:34
閱讀 1180·2019-08-29 10:58
閱讀 1233·2019-08-28 18:22
閱讀 1231·2019-08-26 13:33