摘要:在工廠方法模式中,我們會(huì)遇到一個(gè)問(wèn)題,當(dāng)產(chǎn)品非常多時(shí),繼續(xù)使用工廠方法模式會(huì)產(chǎn)生非常多的工廠類。從簡(jiǎn)單工廠模式到抽象工廠模式,我們都是在用后一種模式解決前一種模式的缺陷,都是在最大程度降低代碼的耦合性。
單例模式
所謂單例模式,也就是說(shuō)不管什么時(shí)候我們要確保只有一個(gè)對(duì)象實(shí)例存在。很多情況下,整個(gè)系統(tǒng)中只需要存在一個(gè)對(duì)象,所有的信息都從這個(gè)對(duì)象獲取,比如系統(tǒng)的配置對(duì)象,或者是線程池。這些場(chǎng)景下,就非常適合使用單例模式??偨Y(jié)起來(lái),就是說(shuō)不管我們初始化一個(gè)對(duì)象多少次,真正干活的對(duì)象只會(huì)生成一次并且在首次生成。
我們可以使用單例模式來(lái)保證連接數(shù)據(jù)庫(kù)只會(huì)發(fā)生一次。下面我們看看一個(gè)簡(jiǎn)單的 Flask Web 框架的 sqlite 擴(kuò)展。
-- 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 擴(kuò)展的初始化方式 """ app.config.setdefault("SQLITE3_DATABASE", ":memory:") app.teardown_appcontext(self.teardown) def connect(self): """ 連接到 sqlite 數(shù)據(jù)庫(kù) """ 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ù)庫(kù)鏈接時(shí)都通過(guò) 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ù)庫(kù)的時(shí)候通過(guò) SQLite3.connection 獲取數(shù)據(jù)庫(kù)連接就可以了。SQLite3.connection保證了數(shù)據(jù)庫(kù)連接只會(huì)發(fā)生一次,其原理和之前我們實(shí)現(xiàn)單例模式的方式相同,只不過(guò)這里存儲(chǔ)實(shí)例的地方變成 flask._app_ctx_stack了。
可以看到單例模式的實(shí)現(xiàn)只需要找一個(gè)變量存放創(chuàng)建的實(shí)例,然后每次獲取實(shí)例時(shí),先檢查變量中是否已保存實(shí)例,如果沒(méi)有則創(chuàng)建一個(gè)實(shí)例并將其存放到變量中,以后都從這個(gè)變量中獲取實(shí)例就可以了。單例模式中,只會(huì)創(chuàng)建一次實(shí)例。
工廠模式
“工廠”兩字,一目了然。所謂工廠模式,也就是說(shuō)我們可以通過(guò)工廠類創(chuàng)建產(chǎn)品。
在工廠方法模式中,我們會(huì)遇到一個(gè)問(wèn)題,當(dāng)產(chǎn)品非常多時(shí),繼續(xù)使用工廠方法模式會(huì)產(chǎn)生非常多的工廠類。
現(xiàn)在我們有一個(gè)產(chǎn)品是課程,但是僅僅依靠課程還沒(méi)辦法提供完美的服務(wù),因?yàn)樵?實(shí)驗(yàn)樓 你可以邊學(xué)課程邊做實(shí)驗(yàn)?zāi)亍T谀睦镒鰧?shí)驗(yàn)?zāi)???dāng)然是在虛擬機(jī)里了。當(dāng)然我們也有很多種虛擬機(jī),比如 Linux 虛擬機(jī)和 Mac 虛擬機(jī)。
如果按照工廠方法模式的作法,我們需要?jiǎng)?chuàng)建 Linux 虛擬機(jī)工廠類和 Mac 虛擬機(jī)工廠類, 這樣我們就會(huì)有一堆工廠類了。但是在 實(shí)驗(yàn)樓 里,真正的情況是只有虛擬機(jī)和課程結(jié)合在一起才能給用戶提供完美的服務(wù)。我們就不能創(chuàng)建出一個(gè)能同時(shí)創(chuàng)建課程和虛擬機(jī)的工廠嗎?因?yàn)槲覀冎榔鋵?shí)用戶的需求同時(shí)包含了課程和虛擬機(jī),如果有一座工廠能同時(shí)生產(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):
""" 項(xiàng)目課 """ def get_labs(self): return "project_course: labs" def __str__(self): return "ProjectCourse"兩種類型的虛擬機(jī)
class LinuxVm(object):
""" Linux 虛擬機(jī) """ def start(self): return "Linux vm running"
class MacVm(object):
""" Mac OSX 虛擬機(jī) """ def start(self): return "Mac OSX vm running"
class Factory(metaclass=abc.ABCMeta):
""" 抽象工廠類, 現(xiàn)在工廠類不僅能創(chuàng)建課程,還能創(chuàng)建虛擬機(jī)了 """ @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):
""" 項(xiàng)目課程工廠類 """ def create_course(self): return ProjectCourse() def create_vm(self): return MacVm()
def get_factory():
""" 隨機(jī)獲取一個(gè)工廠類 """ 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())
抽象工廠模式順利的解決了工廠方法模式中遇到的問(wèn)題,我們通過(guò)將產(chǎn)品的創(chuàng)建進(jìn)行組合放入一個(gè)工廠類中,不但減少了工廠類的數(shù)量,還增加了生產(chǎn)產(chǎn)品體系的能力(比如課程和虛擬機(jī)組成了一個(gè)產(chǎn)品體系)實(shí)驗(yàn)樓?,F(xiàn)在,工廠類不僅僅能創(chuàng)建課程,還能創(chuàng)建虛擬機(jī),我們只需要一座工廠就能為 實(shí)驗(yàn)樓 用戶服務(wù)啦 。
從簡(jiǎn)單工廠模式到抽象工廠模式,我們都是在用后一種模式解決前一種模式的缺陷,都是在最大程度降低代碼的耦合性。在使用工廠模式家族時(shí),不管使用哪一種工廠模式,只要能達(dá)到最大程度的解耦,都是不錯(cuò)的選擇。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/44121.html
摘要:最近開(kāi)展了三次設(shè)計(jì)模式的公開(kāi)課,現(xiàn)在來(lái)總結(jié)一下設(shè)計(jì)模式在中的應(yīng)用,這是第一篇?jiǎng)?chuàng)建型模式之單例模式。不過(guò)因?yàn)椴恢С侄嗑€程所以不需要考慮這個(gè)問(wèn)題了。 最近開(kāi)展了三次設(shè)計(jì)模式的公開(kāi)課,現(xiàn)在來(lái)總結(jié)一下設(shè)計(jì)模式在PHP中的應(yīng)用,這是第一篇?jiǎng)?chuàng)建型模式之單例模式。 一、設(shè)計(jì)模式簡(jiǎn)介 首先我們來(lái)認(rèn)識(shí)一下什么是設(shè)計(jì)模式: 設(shè)計(jì)模式是一套被反復(fù)使用、容易被他人理解的、可靠的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。 設(shè)計(jì)模式不...
摘要:總之,選擇單例模式就是為了避免不一致?tīng)顟B(tài),避免政出多頭。二餓漢式單例餓漢式單例類在類初始化時(shí),已經(jīng)自行實(shí)例化靜態(tài)工廠方法餓漢式在類創(chuàng)建的同時(shí)就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供系統(tǒng)使用,以后不再改變,所以天生是線程安全的。 概念: Java中單例模式是一種常見(jiàn)的設(shè)計(jì)模式,單例模式的寫(xiě)法有好幾種,這里主要介紹兩種:懶漢式單例、餓漢式單例?! 卫J接幸韵绿攸c(diǎn): 1、單例類只能有一個(gè)實(shí)例?!?..
摘要:博主按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語(yǔ)言實(shí)現(xiàn)。單例模式用途如果一個(gè)類負(fù)責(zé)連接數(shù)據(jù)庫(kù)的線程池日志記錄邏輯等等,此時(shí)需要單例模式來(lái)保證對(duì)象不被重復(fù)創(chuàng)建,以達(dá)到降低開(kāi)銷的目的。 博主按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語(yǔ)言實(shí)現(xiàn)。誠(chéng)然,每種設(shè)計(jì)模式都有多種實(shí)...
摘要:博主按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語(yǔ)言實(shí)現(xiàn)。單例模式用途如果一個(gè)類負(fù)責(zé)連接數(shù)據(jù)庫(kù)的線程池日志記錄邏輯等等,此時(shí)需要單例模式來(lái)保證對(duì)象不被重復(fù)創(chuàng)建,以達(dá)到降低開(kāi)銷的目的。 博主按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會(huì)設(shè)計(jì)模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語(yǔ)言實(shí)現(xiàn)。誠(chéng)然,每種設(shè)計(jì)模式都有多種實(shí)...
摘要:輸出結(jié)果輸出結(jié)果此外還有兩種實(shí)現(xiàn)單例的方式,我呢也給大家列出來(lái),方便大家學(xué)習(xí)和參考方式一方式二單例模式實(shí)現(xiàn)方式二。。。 什么是單例模式?通俗點(diǎn)講:?jiǎn)卫J骄褪窃诔绦驁?zhí)行的過(guò)程中,類只有一個(gè)實(shí)例,這不是說(shuō)單例模式只能去創(chuàng)建一個(gè)實(shí)例,而是你創(chuàng)建的所有實(shí)例(也就是對(duì)象)都指的是同一個(gè)實(shí)例。如何做到這一點(diǎn)呢?我們的__new__特殊方法就派上用場(chǎng)了,可能大家對(duì)這個(gè)方法熟悉又陌生,那么接下來(lái)通過(guò)...
閱讀 3243·2021-10-27 14:20
閱讀 2525·2021-10-08 10:05
閱讀 1625·2021-09-09 09:33
閱讀 2902·2019-08-30 13:16
閱讀 1435·2019-08-29 18:34
閱讀 1171·2019-08-29 10:58
閱讀 1228·2019-08-28 18:22
閱讀 1226·2019-08-26 13:33