摘要:設(shè)計(jì)模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。設(shè)計(jì)模式的類型共有種設(shè)計(jì)模式。工廠模式工廠模式最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
該文建議配合 design-patterns-for-humans 中文版 一起看。推薦閱讀
超全的設(shè)計(jì)模式簡(jiǎn)介(45種)
design-patterns-for-humans 中文版(github 倉(cāng)庫(kù)永久更新)
MongoDB 資源、庫(kù)、工具、應(yīng)用程序精選列表中文版
有哪些鮮為人知,但是很有意思的網(wǎng)站?
一份攻城獅筆記
每天搜集 Github 上優(yōu)秀的項(xiàng)目
一些有趣的民間故事
超好用的谷歌瀏覽器、Sublime Text、Phpstorm、油猴插件合集
設(shè)計(jì)模式(Design pattern)代表了最佳的實(shí)踐,通常被有經(jīng)驗(yàn)的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計(jì)模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當(dāng)長(zhǎng)的一段時(shí)間的試驗(yàn)和錯(cuò)誤總結(jié)出來的。設(shè)計(jì)模式的類型
設(shè)計(jì)模式是一套被反復(fù)使用的、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理地運(yùn)用設(shè)計(jì)模式可以完美地解決很多問題,每種模式在現(xiàn)實(shí)中都有相應(yīng)的原理來與之對(duì)應(yīng),每種模式都描述了一個(gè)在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的核心解決方案,這也是設(shè)計(jì)模式能被廣泛應(yīng)用的原因。
共有 23 種設(shè)計(jì)模式。這些模式可以分為三大類:
創(chuàng)建型模式(Creational Patterns)- 這些設(shè)計(jì)模式提供了一種在創(chuàng)建對(duì)象的同時(shí)隱藏創(chuàng)建邏輯的方式,而不是使用 new 運(yùn)算符直接實(shí)例化對(duì)象。這使得程序在判斷針對(duì)某個(gè)給定實(shí)例需要?jiǎng)?chuàng)建哪些對(duì)象時(shí)更加靈活。
工廠模式(Factory Pattern)
抽象工廠模式(Abstract Factory Pattern)
單例模式(Singleton Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
對(duì)象池模式 *(Pool)
多例模式 *(Multiton)
靜態(tài)工廠模式 *(Static Factory)
結(jié)構(gòu)型模式(Structural Patterns)- 這些設(shè)計(jì)模式關(guān)注類和對(duì)象的組合。繼承的概念被用來組合接口和定義組合對(duì)象獲得新功能的方式。
適配器模式(Adapter Pattern)
橋接模式(Bridge Pattern)
過濾器模式(Filter、Criteria Pattern)
組合模式(Composite Pattern)
裝飾器模式(Decorator Pattern)
外觀模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
數(shù)據(jù)映射模式 *(Data Mapper)
依賴注入模式 *(Dependency Injection)
門面模式 *(Facade)
流接口模式 *(Fluent Interface)
注冊(cè)模式 *(Registry)
行為型模式(Behavioral Patterns)- 這些設(shè)計(jì)模式特別關(guān)注對(duì)象之間的通信。
責(zé)任鏈模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解釋器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
備忘錄模式(Memento Pattern)
觀察者模式(Observer Pattern)
狀態(tài)模式(State Pattern)
空對(duì)象模式(Null Object Pattern)
策略模式(Strategy Pattern)
模板模式(Template Pattern)
訪問者模式(Visitor Pattern)
規(guī)格模式 *(Specification)
訪問者模式 *(Visitor)
J2EE 設(shè)計(jì)模式 - 這些設(shè)計(jì)模式特別關(guān)注表示層。這些模式是由 Sun Java Center 鑒定的。
MVC模式(MVC Pattern)
業(yè)務(wù)代表模式(Business Delegate Pattern)
組合實(shí)體模式(Composite Entity Pattern)
數(shù)據(jù)訪問對(duì)象模式(Data Access Object Pattern)
前端控制器模式(Front Controller Pattern)
攔截過濾器模式(Intercepting Filter Pattern)
服務(wù)定位器模式(Service Locator Pattern)
傳輸對(duì)象模式(Transfer Object Pattern)
委托模式 *(Delegation)
資源庫(kù)模式 *(Repository)
下面用一個(gè)圖片來整體描述一下設(shè)計(jì)模式之間的關(guān)系:
設(shè)計(jì)模式的六大原則 1、開閉原則(Open Close Principle)開閉原則的意思是:對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。在程序需要進(jìn)行拓展的時(shí)候,不能去修改原有的代碼,實(shí)現(xiàn)一個(gè)熱插拔的效果。簡(jiǎn)言之,是為了使程序的擴(kuò)展性好,易于維護(hù)和升級(jí)。想要達(dá)到這樣的效果,我們需要使用接口和抽象類,后面的具體設(shè)計(jì)中我們會(huì)提到這點(diǎn)。
2、里氏代換原則(Liskov Substitution Principle)里氏代換原則是面向?qū)ο笤O(shè)計(jì)的基本原則之一。 里氏代換原則中說,任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。LSP 是繼承復(fù)用的基石,只有當(dāng)派生類可以替換掉基類,且軟件單位的功能不受到影響時(shí),基類才能真正被復(fù)用,而派生類也能夠在基類的基礎(chǔ)上增加新的行為。里氏代換原則是對(duì)開閉原則的補(bǔ)充。實(shí)現(xiàn)開閉原則的關(guān)鍵步驟就是抽象化,而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn),所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范。
3、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)這個(gè)原則是開閉原則的基礎(chǔ),具體內(nèi)容:針對(duì)接口編程,依賴于抽象而不依賴于具體。
4、接口隔離原則(Interface Segregation Principle)這個(gè)原則的意思是:使用多個(gè)隔離的接口,比使用單個(gè)接口要好。它還有另外一個(gè)意思是:降低類之間的耦合度。由此可見,其實(shí)設(shè)計(jì)模式就是從大型軟件架構(gòu)出發(fā)、便于升級(jí)和維護(hù)的軟件設(shè)計(jì)思想,它強(qiáng)調(diào)降低依賴,降低耦合。
5、迪米特法則,又稱最少知道原則(Demeter Principle)最少知道原則是指:一個(gè)實(shí)體應(yīng)當(dāng)盡量少地與其他實(shí)體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立。
6、合成復(fù)用原則(Composite Reuse Principle)合成復(fù)用原則是指:盡量使用合成 / 聚合的方式,而不是使用繼承。
工廠模式工廠模式(Factory Pattern)最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。介紹
在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過使用一個(gè)共同的接口來指向新創(chuàng)建的對(duì)象。
意圖: 定義一個(gè)創(chuàng)建對(duì)象的接口,讓其子類自己決定實(shí)例化哪一個(gè)工廠類,工廠模式使其創(chuàng)建過程延遲到子類進(jìn)行。
主要解決: 主要解決接口選擇的問題。
何時(shí)使用: 我們明確地計(jì)劃不同條件下創(chuàng)建不同實(shí)例時(shí)。
如何解決: 讓其子類實(shí)現(xiàn)工廠接口,返回的也是一個(gè)抽象的產(chǎn)品。
關(guān)鍵代碼: 創(chuàng)建過程在其子類執(zhí)行。
應(yīng)用實(shí)例:
您需要一輛汽車,可以直接從工廠里面提貨,而不用去管這輛汽車是怎么做出來的,以及這個(gè)汽車?yán)锩娴木唧w實(shí)現(xiàn)。
Hibernate 換數(shù)據(jù)庫(kù)只需換方言和驅(qū)動(dòng)就可以。
優(yōu)點(diǎn):
一個(gè)調(diào)用者想創(chuàng)建一個(gè)對(duì)象,只要知道其名稱就可以了。
擴(kuò)展性高,如果想增加一個(gè)產(chǎn)品,只要擴(kuò)展一個(gè)工廠類就可以。
屏蔽產(chǎn)品的具體實(shí)現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。
缺點(diǎn): 每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠,使得系統(tǒng)中類的個(gè)數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)也增加了系統(tǒng)具體類的依賴。這并不是什么好事。
使用場(chǎng)景:
日志記錄器:記錄可能記錄到本地硬盤、系統(tǒng)事件、遠(yuǎn)程服務(wù)器等,用戶可以選擇記錄日志到什么地方。
數(shù)據(jù)庫(kù)訪問,當(dāng)用戶不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫(kù),以及數(shù)據(jù)庫(kù)可能有變化時(shí)。
設(shè)計(jì)一個(gè)連接服務(wù)器的框架,需要三個(gè)協(xié)議,"POP3"、"IMAP"、"HTTP",可以把這三個(gè)作為產(chǎn)品類,共同實(shí)現(xiàn)一個(gè)接口。
注意事項(xiàng): 作為一種創(chuàng)建類模式,在任何需要生成復(fù)雜對(duì)象的地方,都可以使用工廠方法模式。有一點(diǎn)需要注意的地方就是復(fù)雜對(duì)象適合使用工廠模式,而簡(jiǎn)單對(duì)象,特別是只需要通過 new 就可以完成創(chuàng)建的對(duì)象,無需使用工廠模式。如果使用工廠模式,就需要引入一個(gè)工廠類,會(huì)增加系統(tǒng)的復(fù)雜度。
抽象工廠模式抽象工廠模式(Abstract Factory Pattern)是圍繞一個(gè)超級(jí)工廠創(chuàng)建其他工廠。該超級(jí)工廠又稱為其他工廠的工廠。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。介紹
在抽象工廠模式中,接口是負(fù)責(zé)創(chuàng)建一個(gè)相關(guān)對(duì)象的工廠,不需要顯式指定它們的類。每個(gè)生成的工廠都能按照工廠模式提供對(duì)象。
意圖: 提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無需指定它們具體的類。
主要解決: 主要解決接口選擇的問題。
何時(shí)使用: 系統(tǒng)的產(chǎn)品有多于一個(gè)的產(chǎn)品族,而系統(tǒng)只消費(fèi)其中某一族的產(chǎn)品。
如何解決: 在一個(gè)產(chǎn)品族里面,定義多個(gè)產(chǎn)品。
關(guān)鍵代碼: 在一個(gè)工廠里聚合多個(gè)同類產(chǎn)品。
應(yīng)用實(shí)例: 工作了,為了參加一些聚會(huì),肯定有兩套或多套衣服吧,比如說有商務(wù)裝(成套,一系列具體產(chǎn)品)、時(shí)尚裝(成套,一系列具體產(chǎn)品),甚至對(duì)于一個(gè)家庭來說,可能有商務(wù)女裝、商務(wù)男裝、時(shí)尚女裝、時(shí)尚男裝,這些也都是成套的,即一系列具體產(chǎn)品。假設(shè)一種情況(現(xiàn)實(shí)中是不存在的,要不然,沒法進(jìn)入共產(chǎn)主義了,但有利于說明抽象工廠模式),在您的家中,某一個(gè)衣柜(具體工廠)只能存放某一種這樣的衣服(成套,一系列具體產(chǎn)品),每次拿這種成套的衣服時(shí)也自然要從這個(gè)衣柜中取出了。用 OO 的思想去理解,所有的衣柜(具體工廠)都是衣柜類的(抽象工廠)某一個(gè),而每一件成套的衣服又包括具體的上衣(某一具體產(chǎn)品),褲子(某一具體產(chǎn)品),這些具體的上衣其實(shí)也都是上衣(抽象產(chǎn)品),具體的褲子也都是褲子(另一個(gè)抽象產(chǎn)品)。
優(yōu)點(diǎn): 當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。
缺點(diǎn): 產(chǎn)品族擴(kuò)展非常困難,要增加一個(gè)系列的某一產(chǎn)品,既要在抽象的 Creator 里加代碼,又要在具體的里面加代碼。
使用場(chǎng)景:
QQ 換皮膚,一整套一起換。
生成不同操作系統(tǒng)的程序。
注意事項(xiàng): 產(chǎn)品族難擴(kuò)展,產(chǎn)品等級(jí)易擴(kuò)展。
單例模式單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供了一種訪問其唯一的對(duì)象的方式,可以直接訪問,不需要實(shí)例化該類的對(duì)象。
注意:
1、單例類只能有一個(gè)實(shí)例。
2、單例類必須自己創(chuàng)建自己的唯一實(shí)例。
3、單例類必須給所有其他對(duì)象提供這一實(shí)例。
介紹意圖: 保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
主要解決: 一個(gè)全局使用的類頻繁地創(chuàng)建與銷毀。
何時(shí)使用: 當(dāng)您想控制實(shí)例數(shù)目,節(jié)省系統(tǒng)資源的時(shí)候。
如何解決: 判斷系統(tǒng)是否已經(jīng)有這個(gè)單例,如果有則返回,如果沒有則創(chuàng)建。
關(guān)鍵代碼: 構(gòu)造函數(shù)是私有的。
應(yīng)用實(shí)例:
一個(gè)班級(jí)只有一個(gè)班主任。
Windows 是多進(jìn)程多線程的,在操作一個(gè)文件的時(shí)候,就不可避免地出現(xiàn)多個(gè)進(jìn)程或線程同時(shí)操作一個(gè)文件的現(xiàn)象,所以所有文件的處理必須通過唯一的實(shí)例來進(jìn)行。
一些設(shè)備管理器常常設(shè)計(jì)為單例模式,比如一個(gè)電腦有兩臺(tái)打印機(jī),在輸出的時(shí)候就要處理不能兩臺(tái)打印機(jī)打印同一個(gè)文件。
優(yōu)點(diǎn):
在內(nèi)存里只有一個(gè)實(shí)例,減少了內(nèi)存的開銷,尤其是頻繁的創(chuàng)建和銷毀實(shí)例(比如管理學(xué)院首頁(yè)頁(yè)面緩存)。
避免對(duì)資源的多重占用(比如寫文件操作)。
缺點(diǎn): 沒有接口,不能繼承,與單一職責(zé)原則沖突,一個(gè)類應(yīng)該只關(guān)心內(nèi)部邏輯,而不關(guān)心外面怎么樣來實(shí)例化。
使用場(chǎng)景:
要求生產(chǎn)唯一序列號(hào)。
WEB 中的計(jì)數(shù)器,不用每次刷新都在數(shù)據(jù)庫(kù)里加一次,用單例先緩存起來。
創(chuàng)建的一個(gè)對(duì)象需要消耗的資源過多,比如 I/O 與數(shù)據(jù)庫(kù)的連接等。
注意事項(xiàng):getInstance() 方法中需要使用同步鎖 synchronized (Singleton.class) 防止多線程同時(shí)進(jìn)入造成 instance 被多次實(shí)例化。
建造者模式建造者模式(Builder Pattern)使用多個(gè)簡(jiǎn)單的對(duì)象一步一步構(gòu)建成一個(gè)復(fù)雜的對(duì)象。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。介紹
一個(gè) Builder 類會(huì)一步一步構(gòu)造最終的對(duì)象。該 Builder 類是獨(dú)立于其他對(duì)象的。
意圖: 將一個(gè)復(fù)雜的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
主要解決: 主要解決在軟件系統(tǒng)中,有時(shí)候面臨著 "一個(gè)復(fù)雜對(duì)象" 的創(chuàng)建工作,其通常由各個(gè)部分的子對(duì)象用一定的算法構(gòu)成;由于需求的變化,這個(gè)復(fù)雜對(duì)象的各個(gè)部分經(jīng)常面臨著劇烈的變化,但是將它們組合在一起的算法卻相對(duì)穩(wěn)定。
何時(shí)使用: 一些基本部件不會(huì)變,而其組合經(jīng)常變化的時(shí)候。
如何解決: 將變與不變分離開。
關(guān)鍵代碼: 建造者:創(chuàng)建和提供實(shí)例,導(dǎo)演:管理建造出來的實(shí)例的依賴關(guān)系。
應(yīng)用實(shí)例:
去肯德基,漢堡、可樂、薯?xiàng)l、炸雞翅等是不變的,而其組合是經(jīng)常變化的,生成出所謂的 "套餐"。
JAVA 中的 StringBuilder。
優(yōu)點(diǎn):
建造者獨(dú)立,易擴(kuò)展。
便于控制細(xì)節(jié)風(fēng)險(xiǎn)。
缺點(diǎn):
產(chǎn)品必須有共同點(diǎn),范圍有限制。
如內(nèi)部變化復(fù)雜,會(huì)有很多的建造類。
使用場(chǎng)景:
需要生成的對(duì)象具有復(fù)雜的內(nèi)部結(jié)構(gòu)。
需要生成的對(duì)象內(nèi)部屬性本身相互依賴。
注意事項(xiàng): 與工廠模式的區(qū)別是:建造者模式更加關(guān)注與零件裝配的順序。
原型模式原型模式(Prototype Pattern)是用于創(chuàng)建重復(fù)的對(duì)象,同時(shí)又能保證性能。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。介紹
這種模式是實(shí)現(xiàn)了一個(gè)原型接口,該接口用于創(chuàng)建當(dāng)前對(duì)象的克隆。當(dāng)直接創(chuàng)建對(duì)象的代價(jià)比較大時(shí),則采用這種模式。例如,一個(gè)對(duì)象需要在一個(gè)高代價(jià)的數(shù)據(jù)庫(kù)操作之后被創(chuàng)建。我們可以緩存該對(duì)象,在下一個(gè)請(qǐng)求時(shí)返回它的克隆,在需要的時(shí)候更新數(shù)據(jù)庫(kù),以此來減少數(shù)據(jù)庫(kù)調(diào)用。
意圖: 用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這些原型創(chuàng)建新的對(duì)象。
主要解決: 在運(yùn)行期建立和刪除原型。
何時(shí)使用:
當(dāng)一個(gè)系統(tǒng)應(yīng)該獨(dú)立于它的產(chǎn)品創(chuàng)建,構(gòu)成和表示時(shí)。
當(dāng)要實(shí)例化的類是在運(yùn)行時(shí)刻指定時(shí),例如,通過動(dòng)態(tài)裝載。
為了避免創(chuàng)建一個(gè)與產(chǎn)品類層次平行的工廠類層次時(shí)。
當(dāng)一個(gè)類的實(shí)例只能有幾個(gè)不同狀態(tài)組合中的一種時(shí)。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實(shí)例化該類更方便一些。
如何解決: 利用已有的一個(gè)原型對(duì)象,快速地生成和原型對(duì)象一樣的實(shí)例。
關(guān)鍵代碼:
實(shí)現(xiàn)克隆操作,在 JAVA 繼承 Cloneable,重寫 clone(),在 .NET 中可以使用 Object 類的 MemberwiseClone() 方法來實(shí)現(xiàn)對(duì)象的淺拷貝或通過序列化的方式來實(shí)現(xiàn)深拷貝。
原型模式同樣用于隔離類對(duì)象的使用者和具體類型(易變類)之間的耦合關(guān)系,它同樣要求這些 "易變類" 擁有穩(wěn)定的接口。
應(yīng)用實(shí)例:
細(xì)胞分裂。
JAVA 中的 Object clone() 方法。
優(yōu)點(diǎn):
性能提高。
逃避構(gòu)造函數(shù)的約束。
缺點(diǎn):
配備克隆方法需要對(duì)類的功能進(jìn)行通盤考慮,這對(duì)于全新的類不是很難,但對(duì)于已有的類不一定很容易,特別當(dāng)一個(gè)類引用不支持串行化的間接對(duì)象,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。
必須實(shí)現(xiàn) Cloneable 接口。
使用場(chǎng)景:
資源優(yōu)化場(chǎng)景。
類初始化需要消化非常多的資源,這個(gè)資源包括數(shù)據(jù). 硬件資源等。
性能和安全要求的場(chǎng)景。
通過 new 產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限,則可以使用原型模式。
一個(gè)對(duì)象多個(gè)修改者的場(chǎng)景。
一個(gè)對(duì)象需要提供給其他對(duì)象訪問,而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以考慮使用原型模式拷貝多個(gè)對(duì)象供調(diào)用者使用。
在實(shí)際項(xiàng)目中,原型模式很少多帶帶出現(xiàn),一般是和工廠方法模式一起出現(xiàn),通過 clone 的方法創(chuàng)建一個(gè)對(duì)象,然后由工廠方法提供給調(diào)用者。原型模式已經(jīng)與 Java 融為渾然一體,大家可以隨手拿來使用。
注意事項(xiàng): 與通過對(duì)一個(gè)類進(jìn)行實(shí)例化來構(gòu)造新對(duì)象不同的是,原型模式是通過拷貝一個(gè)現(xiàn)有對(duì)象生成新對(duì)象的。淺拷貝實(shí)現(xiàn) Cloneable,重寫,深拷貝是通過實(shí)現(xiàn) Serializable 讀取二進(jìn)制流。
對(duì)象池模式對(duì)象池(也稱為資源池)被用來管理對(duì)象緩存。對(duì)象池是一組已經(jīng)初始化過且可以直接使用的對(duì)象集合,用戶在使用對(duì)象時(shí)可以從對(duì)象池中獲取對(duì)象,對(duì)其進(jìn)行操作處理,并在不需要時(shí)歸還給對(duì)象池而非銷毀它。示例代碼 Pool.php
若對(duì)象初始化、實(shí)例化的代價(jià)高,且需要經(jīng)常實(shí)例化,但每次實(shí)例化的數(shù)量較少的情況下,使用對(duì)象池可以獲得顯著的性能提升。常見的使用對(duì)象池模式的技術(shù)包括線程池、數(shù)據(jù)庫(kù)連接池、任務(wù)隊(duì)列池、圖片資源對(duì)象池等。
當(dāng)然,如果要實(shí)例化的對(duì)象較小,不需要多少資源開銷,就沒有必要使用對(duì)象池模式了,這非但不會(huì)提升性能,反而浪費(fèi)內(nèi)存空間,甚至降低性能。
class = $class; } public function get() { if (count($this->instances) > 0) { return array_pop($this->instances); } return new $this->class(); } public function dispose($instance) { $this->instances[] = $instance; } }Processor.php
pool = $pool; } public function process($image) { if ($this->processing++ < $this->maxProcesses) { $this->createWorker($image); } else { $this->pushToWaitingQueue($image); } } private function createWorker($image) { $worker = $this->pool->get(); $worker->run($image, array($this, "processDone")); } public function processDone($worker) { $this->processing--; $this->pool->dispose($worker); if (count($this->waitingQueue) > 0) { $this->createWorker($this->popFromWaitingQueue()); } } private function pushToWaitingQueue($image) { $this->waitingQueue[] = $image; } private function popFromWaitingQueue() { return array_pop($this->waitingQueue); } }Worker.php
多例模式多例模式和單例模式類似,但可以返回多個(gè)實(shí)例。比如我們有多個(gè)數(shù)據(jù)庫(kù)連接,MySQL、SQLite、Postgres,又或者我們有多個(gè)日志記錄器,分別用于記錄調(diào)試信息和錯(cuò)誤信息,這些都可以使用多例模式實(shí)現(xiàn)。示例代碼 Multiton.php靜態(tài)工廠模式與簡(jiǎn)單工廠類似,該模式用于創(chuàng)建一組相關(guān)或依賴的對(duì)象,不同之處在于靜態(tài)工廠模式使用一個(gè)靜態(tài)方法來創(chuàng)建所有類型的對(duì)象,該靜態(tài)方法通常是 factory 或 build。示例代碼 StaticFactory.phpFormatterInterface.phpFormatString.php適配器模式適配器模式(Adapter Pattern)是作為兩個(gè)不兼容的接口之間的橋梁。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它結(jié)合了兩個(gè)獨(dú)立接口的功能。介紹
這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)加入獨(dú)立的或不兼容的接口功能。舉個(gè)真實(shí)的例子,讀卡器是作為內(nèi)存卡和筆記本之間的適配器。您將內(nèi)存卡插入讀卡器,再將讀卡器插入筆記本,這樣就可以通過筆記本來讀取內(nèi)存卡。意圖: 將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
主要解決: 主要解決在軟件系統(tǒng)中,常常要將一些 "現(xiàn)存的對(duì)象" 放到新的環(huán)境中,而新環(huán)境要求的接口是現(xiàn)對(duì)象不能滿足的。
何時(shí)使用:
系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要。
想要建立一個(gè)可以重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進(jìn)的類一起工作,這些源類不一定有一致的接口。
通過接口轉(zhuǎn)換,將一個(gè)類插入另一個(gè)類系中。(比如老虎和飛禽,現(xiàn)在多了一個(gè)飛虎,在不增加實(shí)體的需求下,增加一個(gè)適配器,在里面包容一個(gè)虎對(duì)象,實(shí)現(xiàn)飛的接口。)
如何解決: 繼承或依賴(推薦)。
關(guān)鍵代碼: 適配器繼承或依賴已有的對(duì)象,實(shí)現(xiàn)想要的目標(biāo)接口。
應(yīng)用實(shí)例:
美國(guó)電器 110V,中國(guó) 220V,就要有一個(gè)適配器將 110V 轉(zhuǎn)化為 220V。
JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,則要將以前系統(tǒng)的 Enumeration 接口轉(zhuǎn)化為 Iterator 接口,這時(shí)就需要適配器模式。
在 LINUX 上運(yùn)行 WINDOWS 程序。 4. JAVA 中的 jdbc。
優(yōu)點(diǎn):
可以讓任何兩個(gè)沒有關(guān)聯(lián)的類一起運(yùn)行。
提高了類的復(fù)用。
增加了類的透明度。
靈活性好。
缺點(diǎn):
過多地使用適配器,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。比如,明明看到調(diào)用的是 A 接口,其實(shí)內(nèi)部被適配成了 B 接口的實(shí)現(xiàn),一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場(chǎng)災(zāi)難。因此如果不是很有必要,可以不使用適配器,而是直接對(duì)系統(tǒng)進(jìn)行重構(gòu)。
由于 JAVA 至多繼承一個(gè)類,所以至多只能適配一個(gè)適配者類,而且目標(biāo)類必須是抽象類。
使用場(chǎng)景: 有動(dòng)機(jī)地修改一個(gè)正常運(yùn)行的系統(tǒng)的接口,這時(shí)應(yīng)該考慮使用適配器模式。
注意事項(xiàng): 適配器不是在詳細(xì)設(shè)計(jì)時(shí)添加的,而是解決正在服役的項(xiàng)目的問題。
橋接模式橋接(Bridge)是用于把抽象化與實(shí)現(xiàn)化解耦,使得二者可以獨(dú)立變化。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它通過提供抽象化和實(shí)現(xiàn)化之間的橋接結(jié)構(gòu),來實(shí)現(xiàn)二者的解耦。介紹
這種模式涉及到一個(gè)作為橋接的接口,使得實(shí)體類的功能獨(dú)立于接口實(shí)現(xiàn)類。這兩種類型的類可被結(jié)構(gòu)化改變而互不影響。意圖: 將抽象部分與實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立的變化。
主要解決: 在有多種可能會(huì)變化的情況下,用繼承會(huì)造成類爆炸問題,擴(kuò)展起來不靈活。
何時(shí)使用: 實(shí)現(xiàn)系統(tǒng)可能有多個(gè)角度分類,每一種角度都可能變化。
如何解決: 把這種多角度分類分離出來,讓它們獨(dú)立變化,減少它們之間耦合。
關(guān)鍵代碼: 抽象類依賴實(shí)現(xiàn)類。
應(yīng)用實(shí)例:
豬八戒從天蓬元帥轉(zhuǎn)世投胎到豬,轉(zhuǎn)世投胎的機(jī)制將塵世劃分為兩個(gè)等級(jí),即:靈魂和肉體,前者相當(dāng)于抽象化,后者相當(dāng)于實(shí)現(xiàn)化。生靈通過功能的委派,調(diào)用肉體對(duì)象的功能,使得生靈可以動(dòng)態(tài)地選擇。
墻上的開關(guān),可以看到的開關(guān)是抽象的,不用管里面具體怎么實(shí)現(xiàn)的。
優(yōu)點(diǎn):
抽象和實(shí)現(xiàn)的分離。
優(yōu)秀的擴(kuò)展能力。
實(shí)現(xiàn)細(xì)節(jié)對(duì)客戶透明。
缺點(diǎn): 橋接模式的引入會(huì)增加系統(tǒng)的理解與設(shè)計(jì)難度,由于聚合關(guān)聯(lián)關(guān)系建立在抽象層,要求開發(fā)者針對(duì)抽象進(jìn)行設(shè)計(jì)與編程。
使用場(chǎng)景:
如果一個(gè)系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個(gè)層次之間建立靜態(tài)的繼承聯(lián)系,通過橋接模式可以使它們?cè)诔橄髮咏⒁粋€(gè)關(guān)聯(lián)關(guān)系。
對(duì)于那些不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)急劇增加的系統(tǒng),橋接模式尤為適用。
一個(gè)類存在兩個(gè)獨(dú)立變化的維度,且這兩個(gè)維度都需要進(jìn)行擴(kuò)展。
注意事項(xiàng): 對(duì)于兩個(gè)獨(dú)立變化的維度,使用橋接模式再適合不過了。
過濾器模式過濾器模式(Filter Pattern)或標(biāo)準(zhǔn)模式(Criteria Pattern)是一種設(shè)計(jì)模式,這種模式允許開發(fā)人員使用不同的標(biāo)準(zhǔn)來過濾一組對(duì)象,通過邏輯運(yùn)算以解耦的方式把它們連接起來。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它結(jié)合多個(gè)標(biāo)準(zhǔn)來獲得單一標(biāo)準(zhǔn)。組合模式組合模式(Composite Pattern),又叫部分整體模式,是用于把一組相似的對(duì)象當(dāng)作一個(gè)單一的對(duì)象。組合模式依據(jù)樹形結(jié)構(gòu)來組合對(duì)象,用來表示部分以及整體層次。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它創(chuàng)建了對(duì)象組的樹形結(jié)構(gòu)。介紹
這種模式創(chuàng)建了一個(gè)包含自己對(duì)象組的類。該類提供了修改相同對(duì)象組的方式。意圖: 將對(duì)象組合成樹形結(jié)構(gòu)以表示 "部分 - 整體" 的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
主要解決: 它在我們樹型結(jié)構(gòu)的問題中,模糊了簡(jiǎn)單元素和復(fù)雜元素的概念,客戶程序可以向處理簡(jiǎn)單元素一樣來處理復(fù)雜元素,從而使得客戶程序與復(fù)雜元素的內(nèi)部結(jié)構(gòu)解耦。
何時(shí)使用:
您想表示對(duì)象的部分 - 整體層次結(jié)構(gòu)(樹形結(jié)構(gòu))。
您希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。
如何解決: 樹枝和葉子實(shí)現(xiàn)統(tǒng)一接口,樹枝內(nèi)部組合該接口。
關(guān)鍵代碼: 樹枝內(nèi)部組合該接口,并且含有內(nèi)部屬性 List,里面放 Component。
應(yīng)用實(shí)例:
算術(shù)表達(dá)式包括操作數(shù). 操作符和另一個(gè)操作數(shù),其中,另一個(gè)操作符也可以是操作數(shù). 操作符和另一個(gè)操作數(shù)。
在 JAVA AWT 和 SWING 中,對(duì)于 Button 和 Checkbox 是樹葉,Container 是樹枝。
優(yōu)點(diǎn):
高層模塊調(diào)用簡(jiǎn)單。
節(jié)點(diǎn)自由增加。
缺點(diǎn): 在使用組合模式時(shí),其葉子和樹枝的聲明都是實(shí)現(xiàn)類,而不是接口,違反了依賴倒置原則。
使用場(chǎng)景: 部分. 整體場(chǎng)景,如樹形菜單,文件. 文件夾的管理。
注意事項(xiàng): 定義時(shí)為具體類。
裝飾器模式裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝。介紹
這種模式創(chuàng)建了一個(gè)裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。意圖: 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說,裝飾器模式相比生成子類更為靈活。
主要解決: 一般的,我們?yōu)榱藬U(kuò)展一個(gè)類經(jīng)常使用繼承方式實(shí)現(xiàn),由于繼承為類引入靜態(tài)特征,并且隨著擴(kuò)展功能的增多,子類會(huì)很膨脹。
何時(shí)使用: 在不想增加很多子類的情況下擴(kuò)展類。
如何解決: 將具體功能職責(zé)劃分,同時(shí)繼承裝飾者模式。
關(guān)鍵代碼:
Component 類充當(dāng)抽象角色,不應(yīng)該具體實(shí)現(xiàn)。
修飾類引用和繼承 Component 類,具體擴(kuò)展類重寫父類方法。
應(yīng)用實(shí)例:
孫悟空有 72 變,當(dāng)他變成 "廟宇" 后,他的根本還是一只猴子,但是他又有了廟宇的功能。
不論一幅畫有沒有畫框都可以掛在墻上,但是通常都是有畫框的,并且實(shí)際上是畫框被掛在墻上。在掛在墻上之前,畫可以被蒙上玻璃,裝到框子里;這時(shí)畫、玻璃和畫框形成了一個(gè)物體。
優(yōu)點(diǎn): 裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會(huì)相互耦合,裝飾模式是繼承的一個(gè)替代模式,裝飾模式可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能。
缺點(diǎn): 多層裝飾比較復(fù)雜。
使用場(chǎng)景:
擴(kuò)展一個(gè)類的功能。
動(dòng)態(tài)增加功能,動(dòng)態(tài)撤銷。
注意事項(xiàng): 可代替繼承。
外觀模式外觀模式(Facade Pattern)隱藏系統(tǒng)的復(fù)雜性,并向客戶端提供了一個(gè)客戶端可以訪問系統(tǒng)的接口。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它向現(xiàn)有的系統(tǒng)添加一個(gè)接口,來隱藏系統(tǒng)的復(fù)雜性。介紹
這種模式涉及到一個(gè)單一的類,該類提供了客戶端請(qǐng)求的簡(jiǎn)化方法和對(duì)現(xiàn)有系統(tǒng)類方法的委托調(diào)用。意圖: 為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,外觀模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
主要解決: 降低訪問復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)時(shí)的復(fù)雜度,簡(jiǎn)化客戶端與之的接口。
何時(shí)使用:
客戶端不需要知道系統(tǒng)內(nèi)部的復(fù)雜聯(lián)系,整個(gè)系統(tǒng)只需提供一個(gè) "接待員" 即可。
定義系統(tǒng)的入口。
如何解決: 客戶端不與系統(tǒng)耦合,外觀類與系統(tǒng)耦合。
關(guān)鍵代碼: 在客戶端和復(fù)雜系統(tǒng)之間再加一層,這一層將調(diào)用順序. 依賴關(guān)系等處理好。
應(yīng)用實(shí)例:
去醫(yī)院看病,可能要去掛號(hào)、門診、劃價(jià)、取藥,讓患者或患者家屬覺得很復(fù)雜,如果有提供接待人員,只讓接待人員來處理,就很方便。
JAVA 的三層開發(fā)模式。
優(yōu)點(diǎn):
減少系統(tǒng)相互依賴。
提高靈活性。
提高了安全性。
缺點(diǎn): 不符合開閉原則,如果要改東西很麻煩,繼承重寫都不合適。
使用場(chǎng)景:
為復(fù)雜的模塊或子系統(tǒng)提供外界訪問的模塊。
子系統(tǒng)相對(duì)獨(dú)立。
預(yù)防低水平人員帶來的風(fēng)險(xiǎn)。
注意事項(xiàng): 在層次化結(jié)構(gòu)中,可以使用外觀模式定義系統(tǒng)中每一層的入口。
享元模式享元模式(Flyweight Pattern)主要用于減少創(chuàng)建對(duì)象的數(shù)量,以減少內(nèi)存占用和提高性能。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它提供了減少對(duì)象數(shù)量從而改善應(yīng)用所需的對(duì)象結(jié)構(gòu)的方式。介紹
享元模式嘗試重用現(xiàn)有的同類對(duì)象,如果未找到匹配的對(duì)象,則創(chuàng)建新對(duì)象。我們將通過創(chuàng)建 5 個(gè)對(duì)象來畫出 20 個(gè)分布于不同位置的圓來演示這種模式。由于只有 5 種可用的顏色,所以 color 屬性被用來檢查現(xiàn)有的 Circle 對(duì)象。意圖: 運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
主要解決: 在有大量對(duì)象時(shí),有可能會(huì)造成內(nèi)存溢出,我們把其中共同的部分抽象出來,如果有相同的業(yè)務(wù)請(qǐng)求,直接返回在內(nèi)存中已有的對(duì)象,避免重新創(chuàng)建。
何時(shí)使用:
系統(tǒng)中有大量對(duì)象。
這些對(duì)象消耗大量?jī)?nèi)存。
這些對(duì)象的狀態(tài)大部分可以外部化。
這些對(duì)象可以按照內(nèi)蘊(yùn)狀態(tài)分為很多組,當(dāng)把外蘊(yùn)對(duì)象從對(duì)象中剔除出來時(shí),每一組對(duì)象都可以用一個(gè)對(duì)象來代替。
系統(tǒng)不依賴于這些對(duì)象身份,這些對(duì)象是不可分辨的。
如何解決: 用唯一標(biāo)識(shí)碼判斷,如果在內(nèi)存中有,則返回這個(gè)唯一標(biāo)識(shí)碼所標(biāo)識(shí)的對(duì)象。
關(guān)鍵代碼: 用 HashMap 存儲(chǔ)這些對(duì)象。
應(yīng)用實(shí)例:
JAVA 中的 String,如果有則返回,如果沒有則創(chuàng)建一個(gè)字符串保存在字符串緩存池里面。2. 數(shù)據(jù)庫(kù)的數(shù)據(jù)池。
優(yōu)點(diǎn): 大大減少對(duì)象的創(chuàng)建,降低系統(tǒng)的內(nèi)存,使效率提高。
缺點(diǎn): 提高了系統(tǒng)的復(fù)雜度,需要分離出外部狀態(tài)和內(nèi)部狀態(tài),而且外部狀態(tài)具有固有化的性質(zhì),不應(yīng)該隨著內(nèi)部狀態(tài)的變化而變化,否則會(huì)造成系統(tǒng)的混亂。
使用場(chǎng)景:
系統(tǒng)有大量相似對(duì)象。
需要緩沖池的場(chǎng)景。
注意事項(xiàng):
注意劃分外部狀態(tài)和內(nèi)部狀態(tài),否則可能會(huì)引起線程安全問題。
這些類必須有一個(gè)工廠對(duì)象加以控制。
代理模式在代理模式(Proxy Pattern)中,一個(gè)類代表另一個(gè)類的功能。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式。介紹
在代理模式中,我們創(chuàng)建具有現(xiàn)有對(duì)象的對(duì)象,以便向外界提供功能接口。意圖: 為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。
主要解決: 在直接訪問對(duì)象時(shí)帶來的問題,比如說:要訪問的對(duì)象在遠(yuǎn)程的機(jī)器上。在面向?qū)ο笙到y(tǒng)中,有些對(duì)象由于某些原因(比如對(duì)象創(chuàng)建開銷很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪問),直接訪問會(huì)給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩,我們可以在訪問此對(duì)象時(shí)加上一個(gè)對(duì)此對(duì)象的訪問層。
何時(shí)使用: 想在訪問一個(gè)類時(shí)做一些控制。
如何解決: 增加中間層。
關(guān)鍵代碼: 實(shí)現(xiàn)與被代理類組合。
應(yīng)用實(shí)例:
Windows 里面的快捷方式。
豬八戒去找高翠蘭結(jié)果是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實(shí)現(xiàn)了這個(gè)接口,豬八戒訪問高翠蘭的時(shí)候看不出來這個(gè)是孫悟空,所以說孫悟空是高翠蘭代理類。
買火車票不一定在火車站買,也可以去代售點(diǎn)。
一張支票或銀行存單是賬戶中資金的代理。支票在市場(chǎng)交易中用來代替現(xiàn)金,并提供對(duì)簽發(fā)人賬號(hào)上資金的控制。
spring aop。
優(yōu)點(diǎn):
職責(zé)清晰。
高擴(kuò)展性。
智能化。
缺點(diǎn):
由于在客戶端和真實(shí)主題之間增加了代理對(duì)象,因此有些類型的代理模式可能會(huì)造成請(qǐng)求的處理速度變慢。
實(shí)現(xiàn)代理模式需要額外的工作,有些代理模式的實(shí)現(xiàn)非常復(fù)雜。
使用場(chǎng)景: 按職責(zé)來劃分,通常有以下使用場(chǎng)景:
遠(yuǎn)程代理。
虛擬代理。
Copy-on-Write 代理。
保護(hù)(Protect or Access)代理。
Cache 代理。
防火墻(Firewall)代理。
同步化(Synchronization)代理。
智能引用(Smart Reference)代理。
注意事項(xiàng):
和適配器模式的區(qū)別:適配器模式主要改變所考慮對(duì)象的接口,而代理模式不能改變所代理類的接口。
和裝飾器模式的區(qū)別:裝飾器模式為了增強(qiáng)功能,而代理模式是為了加以控制。
數(shù)據(jù)映射模式在了解數(shù)據(jù)映射模式之前,先了解下數(shù)據(jù)映射,它是在持久化數(shù)據(jù)存儲(chǔ)層(通常是關(guān)系型數(shù)據(jù)庫(kù))和駐于內(nèi)存的數(shù)據(jù)表現(xiàn)層之間進(jìn)行雙向數(shù)據(jù)傳輸?shù)臄?shù)據(jù)訪問層。依賴注入模式
數(shù)據(jù)映射模式的目的是讓持久化數(shù)據(jù)存儲(chǔ)層、駐于內(nèi)存的數(shù)據(jù)表現(xiàn)層、以及數(shù)據(jù)映射本身三者相互獨(dú)立、互不依賴。這個(gè)數(shù)據(jù)訪問層由一個(gè)或多個(gè)映射器(或者數(shù)據(jù)訪問對(duì)象)組成,用于實(shí)現(xiàn)數(shù)據(jù)傳輸。通用的數(shù)據(jù)訪問層可以處理不同的實(shí)體類型,而專用的則處理一個(gè)或幾個(gè)。
數(shù)據(jù)映射模式的核心在于它的數(shù)據(jù)模型遵循單一職責(zé)原則(Single Responsibility Principle), 這也是和 Active Record 模式的不同之處。最典型的數(shù)據(jù)映射模式例子就是數(shù)據(jù)庫(kù) ORM 模型 (Object Relational Mapper)。
準(zhǔn)確來說該模式是個(gè)架構(gòu)模式。依賴注入(Dependency Injection)是控制反轉(zhuǎn)(Inversion of Control)的一種實(shí)現(xiàn)方式。門面模式
我們先來看看什么是控制反轉(zhuǎn)。
當(dāng)調(diào)用者需要被調(diào)用者的協(xié)助時(shí),在傳統(tǒng)的程序設(shè)計(jì)過程中,通常由調(diào)用者來創(chuàng)建被調(diào)用者的實(shí)例,但在這里,創(chuàng)建被調(diào)用者的工作不再由調(diào)用者來完成,而是將被調(diào)用者的創(chuàng)建移到調(diào)用者的外部,從而反轉(zhuǎn)被調(diào)用者的創(chuàng)建,消除了調(diào)用者對(duì)被調(diào)用者創(chuàng)建的控制,因此稱為控制反轉(zhuǎn)。
要實(shí)現(xiàn)控制反轉(zhuǎn),通常的解決方案是將創(chuàng)建被調(diào)用者實(shí)例的工作交由 IoC 容器來完成,然后在調(diào)用者中注入被調(diào)用者(通過構(gòu)造器/方法注入實(shí)現(xiàn)),這樣我們就實(shí)現(xiàn)了調(diào)用者與被調(diào)用者的解耦,該過程被稱為依賴注入。
依賴注入不是目的,它是一系列工具和手段,最終的目的是幫助我們開發(fā)出松散耦合(loose coupled)、可維護(hù)、可測(cè)試的代碼和程序。這條原則的做法是大家熟知的面向接口,或者說是面向抽象編程。門面模式(Facade)又稱外觀模式,用于為子系統(tǒng)中的一組接口提供一個(gè)一致的界面。門面模式定義了一個(gè)高層接口,這個(gè)接口使得子系統(tǒng)更加容易使用:引入門面角色之后,用戶只需要直接與門面角色交互,用戶與子系統(tǒng)之間的復(fù)雜關(guān)系由門面角色來實(shí)現(xiàn),從而降低了系統(tǒng)的耦合度。示例代碼 Facade.phpbios = $bios; $this->os = $os; } /** * turn on the system */ public function turnOn() { $this->bios->execute(); $this->bios->waitForKeyPress(); $this->bios->launch($this->os); } /** * turn off the system */ public function turnOff() { $this->os->halt(); $this->bios->powerDown(); } }OsInterface.phpBiosInterface.php流接口模式在軟件工程中,流接口(Fluent Interface)是指實(shí)現(xiàn)一種面向?qū)ο蟮?、能提高代碼可讀性的 API 的方法,其目的就是可以編寫具有自然語(yǔ)言一樣可讀性的代碼,我們對(duì)這種代碼編寫方式還有一個(gè)通俗的稱呼 —— 方法鏈。示例代碼 Sql.php
Laravel 中流接口模式有著廣泛使用,比如查詢構(gòu)建器,郵件等等。fields = $fields; return $this; } /** * 添加 FROM 子句 * * @param string $table * @param string $alias * * @return SQL */ public function from($table, $alias) { $this->from[] = $table . " AS " . $alias; return $this; } /** * 添加 WHERE 條件 * * @param string $condition * * @return SQL */ public function where($condition) { $this->where[] = $condition; return $this; } /** * 生成查詢語(yǔ)句 * * @return string */ public function getQuery() { return "SELECT " . implode(",", $this->fields) . " FROM " . implode(",", $this->from) . " WHERE " . implode(" AND ", $this->where); } }注冊(cè)模式注冊(cè)模式(Registry)也叫做注冊(cè)樹模式,注冊(cè)器模式。注冊(cè)模式為應(yīng)用中經(jīng)常使用的對(duì)象創(chuàng)建一個(gè)中央存儲(chǔ)器來存放這些對(duì)象 —— 通常通過一個(gè)只包含靜態(tài)方法的抽象類來實(shí)現(xiàn)(或者通過單例模式)。示例代碼 Registry.php責(zé)任鏈模式顧名思義,責(zé)任鏈模式(Chain of Responsibility Pattern)為請(qǐng)求創(chuàng)建了一個(gè)接收者對(duì)象的鏈。這種模式給予請(qǐng)求的類型,對(duì)請(qǐng)求的發(fā)送者和接收者進(jìn)行解耦。這種類型的設(shè)計(jì)模式屬于行為型模式。介紹
在這種模式中,通常每個(gè)接收者都包含對(duì)另一個(gè)接收者的引用。如果一個(gè)對(duì)象不能處理該請(qǐng)求,那么它會(huì)把相同的請(qǐng)求傳給下一個(gè)接收者,依此類推。意圖: 避免請(qǐng)求發(fā)送者與接收者耦合在一起,讓多個(gè)對(duì)象都有可能接收請(qǐng)求,將這些對(duì)象連接成一條鏈,并且沿著這條鏈傳遞請(qǐng)求,直到有對(duì)象處理它為止。
主要解決: 職責(zé)鏈上的處理者負(fù)責(zé)處理請(qǐng)求,客戶只需要將請(qǐng)求發(fā)送到職責(zé)鏈上即可,無須關(guān)心請(qǐng)求的處理細(xì)節(jié)和請(qǐng)求的傳遞,所以職責(zé)鏈將請(qǐng)求的發(fā)送者和請(qǐng)求的處理者解耦了。
何時(shí)使用: 在處理消息的時(shí)候以過濾很多道。
如何解決: 攔截的類都實(shí)現(xiàn)統(tǒng)一接口。
關(guān)鍵代碼: Handler 里面聚合它自己,在 HandlerRequest 里判斷是否合適,如果沒達(dá)到條件則向下傳遞,向誰(shuí)傳遞之前 set 進(jìn)去。
應(yīng)用實(shí)例:
紅樓夢(mèng)中的 "擊鼓傳花"。
JS 中的事件冒泡。
JAVA WEB 中 Apache Tomcat 對(duì) Encoding 的處理,Struts2 的攔截器,jsp servlet 的 Filter。
優(yōu)點(diǎn):
降低耦合度。它將請(qǐng)求的發(fā)送者和接收者解耦。
簡(jiǎn)化了對(duì)象。使得對(duì)象不需要知道鏈的結(jié)構(gòu)。
增強(qiáng)給對(duì)象指派職責(zé)的靈活性。通過改變鏈內(nèi)的成員或者調(diào)動(dòng)它們的次序,允許動(dòng)態(tài)地新增或者刪除責(zé)任。
增加新的請(qǐng)求處理類很方便。
缺點(diǎn):
不能保證請(qǐng)求一定被接收。
系統(tǒng)性能將受到一定影響,而且在進(jìn)行代碼調(diào)試時(shí)不太方便,可能會(huì)造成循環(huán)調(diào)用。
可能不容易觀察運(yùn)行時(shí)的特征,有礙于除錯(cuò)。
使用場(chǎng)景:
有多個(gè)對(duì)象可以處理同一個(gè)請(qǐng)求,具體哪個(gè)對(duì)象處理該請(qǐng)求由運(yùn)行時(shí)刻自動(dòng)確定。
在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求。
可動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求。
注意事項(xiàng): 在 JAVA WEB 中遇到很多應(yīng)用。
命令模式命令模式(Command Pattern)是一種數(shù)據(jù)驅(qū)動(dòng)的設(shè)計(jì)模式,它屬于行為型模式。請(qǐng)求以命令的形式包裹在對(duì)象中,并傳給調(diào)用對(duì)象。調(diào)用對(duì)象尋找可以處理該命令的合適的對(duì)象,并把該命令傳給相應(yīng)的對(duì)象,該對(duì)象執(zhí)行命令。介紹意圖: 將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而使您可以用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化。
主要解決: 在軟件系統(tǒng)中,行為請(qǐng)求者與行為實(shí)現(xiàn)者通常是一種緊耦合的關(guān)系,但某些場(chǎng)合,比如需要對(duì)行為進(jìn)行記錄、撤銷或重做、事務(wù)等處理時(shí),這種無法抵御變化的緊耦合的設(shè)計(jì)就不太合適。
何時(shí)使用: 在某些場(chǎng)合,比如要對(duì)行為進(jìn)行 "記錄、撤銷 / 重做、事務(wù)" 等處理,這種無法抵御變化的緊耦合是不合適的。在這種情況下,如何將 "行為請(qǐng)求者" 與 "行為實(shí)現(xiàn)者" 解耦?將一組行為抽象為對(duì)象,可以實(shí)現(xiàn)二者之間的松耦合。
如何解決: 通過調(diào)用者調(diào)用接受者執(zhí)行命令,順序:調(diào)用者→接受者→命令。
關(guān)鍵代碼: 定義三個(gè)角色:
received 真正的命令執(zhí)行對(duì)象
Command
invoker 使用命令對(duì)象的入口
應(yīng)用實(shí)例: struts 1 中的 action 核心控制器 ActionServlet 只有一個(gè),相當(dāng)于 Invoker,而模型層的類會(huì)隨著不同的應(yīng)用有不同的模型類,相當(dāng)于具體的 Command。
優(yōu)點(diǎn):
降低了系統(tǒng)耦合度。
新的命令可以很容易添加到系統(tǒng)中去。
缺點(diǎn): 使用命令模式可能會(huì)導(dǎo)致某些系統(tǒng)有過多的具體命令類。
使用場(chǎng)景: 認(rèn)為是命令的地方都可以使用命令模式,比如:
GUI 中每一個(gè)按鈕都是一條命令。
模擬 CMD。
注意事項(xiàng): 系統(tǒng)需要支持命令的撤銷 (Undo) 操作和恢復(fù) (Redo) 操作,也可以考慮使用命令模式,見命令模式的擴(kuò)展。
解釋器模式解釋器模式(Interpreter Pattern)提供了評(píng)估語(yǔ)言的語(yǔ)法或表達(dá)式的方式,它屬于行為型模式。這種模式實(shí)現(xiàn)了一個(gè)表達(dá)式接口,該接口解釋一個(gè)特定的上下文。這種模式被用在 SQL 解析、符號(hào)處理引擎等。介紹意圖: 給定一個(gè)語(yǔ)言,定義它的文法表示,并定義一個(gè)解釋器,這個(gè)解釋器使用該標(biāo)識(shí)來解釋語(yǔ)言中的句子。
主要解決: 對(duì)于一些固定文法構(gòu)建一個(gè)解釋句子的解釋器。
何時(shí)使用: 如果一種特定類型的問題發(fā)生的頻率足夠高,那么可能就值得將該問題的各個(gè)實(shí)例表述為一個(gè)簡(jiǎn)單語(yǔ)言中的句子。這樣就可以構(gòu)建一個(gè)解釋器,該解釋器通過解釋這些句子來解決該問題。
如何解決: 構(gòu)建語(yǔ)法樹,定義終結(jié)符與非終結(jié)符。
關(guān)鍵代碼: 構(gòu)建環(huán)境類,包含解釋器之外的一些全局信息,一般是 HashMap。
應(yīng)用實(shí)例: 編譯器、運(yùn)算表達(dá)式計(jì)算。
優(yōu)點(diǎn):
可擴(kuò)展性比較好,靈活。
增加了新的解釋表達(dá)式的方式。
易于實(shí)現(xiàn)簡(jiǎn)單文法。
缺點(diǎn):
可利用場(chǎng)景比較少。
對(duì)于復(fù)雜的文法比較難維護(hù)。
解釋器模式會(huì)引起類膨脹。
解釋器模式采用遞歸調(diào)用方法。
使用場(chǎng)景:
可以將一個(gè)需要解釋執(zhí)行的語(yǔ)言中的句子表示為一個(gè)抽象語(yǔ)法樹。
一些重復(fù)出現(xiàn)的問題可以用一種簡(jiǎn)單的語(yǔ)言來進(jìn)行表達(dá)。
一個(gè)簡(jiǎn)單語(yǔ)法需要解釋的場(chǎng)景。
注意事項(xiàng): 可利用場(chǎng)景比較少,JAVA 中如果碰到可以用 expression4J 代替。
迭代器模式迭代器模式(Iterator Pattern)是 Java 和 .Net 編程環(huán)境中非常常用的設(shè)計(jì)模式。這種模式用于順序訪問集合對(duì)象的元素,不需要知道集合對(duì)象的底層表示。介紹
迭代器模式屬于行為型模式。意圖: 提供一種方法順序訪問一個(gè)聚合對(duì)象中各個(gè)元素, 而又無須暴露該對(duì)象的內(nèi)部表示。
主要解決: 不同的方式來遍歷整個(gè)整合對(duì)象。
何時(shí)使用: 遍歷一個(gè)聚合對(duì)象。
如何解決: 把在元素之間游走的責(zé)任交給迭代器,而不是聚合對(duì)象。
關(guān)鍵代碼: 定義接口:hasNext, next。
應(yīng)用實(shí)例: JAVA 中的 iterator。
優(yōu)點(diǎn):
它支持以不同的方式遍歷一個(gè)聚合對(duì)象。
迭代器簡(jiǎn)化了聚合類。
在同一個(gè)聚合上可以有多個(gè)遍歷。
在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有代碼。
缺點(diǎn): 由于迭代器模式將存儲(chǔ)數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離,增加新的聚合類需要對(duì)應(yīng)增加新的迭代器類,類的個(gè)數(shù)成對(duì)增加,這在一定程度上增加了系統(tǒng)的復(fù)雜性。
使用場(chǎng)景:
訪問一個(gè)聚合對(duì)象的內(nèi)容而無須暴露它的內(nèi)部表示。
需要為聚合對(duì)象提供多種遍歷方式。
為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口。
注意事項(xiàng): 迭代器模式就是分離了集合對(duì)象的遍歷行為,抽象出一個(gè)迭代器類來負(fù)責(zé),這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu),又可讓外部代碼透明地訪問集合內(nèi)部的數(shù)據(jù)。
中介者模式中介者模式(Mediator Pattern)是用來降低多個(gè)對(duì)象和類之間的通信復(fù)雜性。這種模式提供了一個(gè)中介類,該類通常處理不同類之間的通信,并支持松耦合,使代碼易于維護(hù)。中介者模式屬于行為型模式。介紹意圖: 用一個(gè)中介對(duì)象來封裝一系列的對(duì)象交互,中介者使各對(duì)象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。
主要解決: 對(duì)象與對(duì)象之間存在大量的關(guān)聯(lián)關(guān)系,這樣勢(shì)必會(huì)導(dǎo)致系統(tǒng)的結(jié)構(gòu)變得很復(fù)雜,同時(shí)若一個(gè)對(duì)象發(fā)生改變,我們也需要跟蹤與之相關(guān)聯(lián)的對(duì)象,同時(shí)做出相應(yīng)的處理。
何時(shí)使用: 多個(gè)類相互耦合,形成了網(wǎng)狀結(jié)構(gòu)。
如何解決: 將上述網(wǎng)狀結(jié)構(gòu)分離為星型結(jié)構(gòu)。
關(guān)鍵代碼: 對(duì)象 Colleague 之間的通信封裝到一個(gè)類中多帶帶處理。
應(yīng)用實(shí)例:
中國(guó)加入 WTO 之前是各個(gè)國(guó)家相互貿(mào)易,結(jié)構(gòu)復(fù)雜,現(xiàn)在是各個(gè)國(guó)家通過 WTO 來互相貿(mào)易。
機(jī)場(chǎng)調(diào)度系統(tǒng)。
MVC 框架,其中 C(控制器)就是 M(模型)和 V(視圖)的中介者。
優(yōu)點(diǎn):
降低了類的復(fù)雜度,將一對(duì)多轉(zhuǎn)化成了一對(duì)一。
各個(gè)類之間的解耦。
符合迪米特原則。
缺點(diǎn): 中介者會(huì)龐大,變得復(fù)雜難以維護(hù)。
使用場(chǎng)景:
系統(tǒng)中對(duì)象之間存在比較復(fù)雜的引用關(guān)系,導(dǎo)致它們之間的依賴關(guān)系結(jié)構(gòu)混亂而且難以復(fù)用該對(duì)象。
想通過一個(gè)中間類來封裝多個(gè)類中的行為,而又不想生成太多的子類。
注意事項(xiàng): 不應(yīng)當(dāng)在職責(zé)混亂的時(shí)候使用。
備忘錄模式備忘錄模式(Memento Pattern)保存一個(gè)對(duì)象的某個(gè)狀態(tài),以便在適當(dāng)?shù)臅r(shí)候恢復(fù)對(duì)象。備忘錄模式屬于行為型模式。
介紹意圖: 在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。
主要解決: 所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),這樣可以在以后將對(duì)象恢復(fù)到原先保存的狀態(tài)。
何時(shí)使用: 很多時(shí)候我們總是需要記錄一個(gè)對(duì)象的內(nèi)部狀態(tài),這樣做的目的就是為了允許用戶取消不確定或者錯(cuò)誤的操作,能夠恢復(fù)到他原先的狀態(tài),使得他有 "后悔藥" 可吃。
如何解決: 通過一個(gè)備忘錄類專門存儲(chǔ)對(duì)象狀態(tài)。
關(guān)鍵代碼: 客戶不與備忘錄類耦合,與備忘錄管理類耦合。
應(yīng)用實(shí)例:
后悔藥。
打游戲時(shí)的存檔。
Windows 里的 ctri + z。
IE 中的后退。
數(shù)據(jù)庫(kù)的事務(wù)管理。
優(yōu)點(diǎn):
給用戶提供了一種可以恢復(fù)狀態(tài)的機(jī)制,可以使用戶能夠比較方便地回到某個(gè)歷史的狀態(tài)。
實(shí)現(xiàn)了信息的封裝,使得用戶不需要關(guān)心狀態(tài)的保存細(xì)節(jié)。
缺點(diǎn): 消耗資源。如果類的成員變量過多,勢(shì)必會(huì)占用比較大的資源,而且每一次保存都會(huì)消耗一定的內(nèi)存。
使用場(chǎng)景:
需要保存 / 恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場(chǎng)景。
提供一個(gè)可回滾的操作。
注意事項(xiàng):
為了符合迪米特原則,還要增加一個(gè)管理備忘錄的類。
為了節(jié)約內(nèi)存,可使用原型模式 + 備忘錄模式。
觀察者模式當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知它的依賴對(duì)象。觀察者模式屬于行為型模式。介紹意圖: 定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。
主要解決: 一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問題,而且要考慮到易用和低耦合,保證高度的協(xié)作。
何時(shí)使用: 一個(gè)對(duì)象(目標(biāo)對(duì)象)的狀態(tài)發(fā)生改變,所有的依賴對(duì)象(觀察者對(duì)象)都將得到通知,進(jìn)行廣播通知。
如何解決: 使用面向?qū)ο蠹夹g(shù),可以將這種依賴關(guān)系弱化。
關(guān)鍵代碼: 在抽象類里有一個(gè) ArrayList 存放觀察者們。
應(yīng)用實(shí)例:
拍賣的時(shí)候,拍賣師觀察最高標(biāo)價(jià),然后通知給其他競(jìng)價(jià)者競(jìng)價(jià)。
西游記里面悟空請(qǐng)求菩薩降服紅孩兒,菩薩灑了一地水招來一個(gè)老烏龜,這個(gè)烏龜就是觀察者,他觀察菩薩灑水這個(gè)動(dòng)作。
優(yōu)點(diǎn):
觀察者和被觀察者是抽象耦合的。
建立一套觸發(fā)機(jī)制。
缺點(diǎn):
如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。
如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰。
觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。
使用場(chǎng)景:
一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一個(gè)方面。將這些方面封裝在獨(dú)立的對(duì)象中使它們可以各自獨(dú)立地改變和復(fù)用。
一個(gè)對(duì)象的改變將導(dǎo)致其他一個(gè)或多個(gè)對(duì)象也發(fā)生改變,而不知道具體有多少對(duì)象將發(fā)生改變,可以
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/74110.html
摘要:設(shè)計(jì)模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。設(shè)計(jì)模式的類型共有種設(shè)計(jì)模式。工廠模式工廠模式最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。 該文建議配合 design-patterns-for-humans 中文版 一起看。 推薦閱讀 超全的設(shè)計(jì)模式簡(jiǎn)介(45種) design-patterns-for-humans 中文版...
摘要:參考配置添加,告訴程序在執(zhí)行前要調(diào)用的服務(wù)或者也可以在修改配置文件,告訴程序在執(zhí)行前要調(diào)用的服務(wù)參考鏈接 showImg(https://segmentfault.com/img/bVbt7t1?w=2880&h=2608); 推薦閱讀 Tideways、xhprof 和 xhgui 打造 PHP 非侵入式監(jiān)控平臺(tái) 超全的設(shè)計(jì)模式簡(jiǎn)介(45種) design-patterns-for...
摘要:參考配置添加,告訴程序在執(zhí)行前要調(diào)用的服務(wù)或者也可以在修改配置文件,告訴程序在執(zhí)行前要調(diào)用的服務(wù)參考鏈接 showImg(https://segmentfault.com/img/bVbt7t1?w=2880&h=2608); 推薦閱讀 Tideways、xhprof 和 xhgui 打造 PHP 非侵入式監(jiān)控平臺(tái) 超全的設(shè)計(jì)模式簡(jiǎn)介(45種) design-patterns-for...
閱讀 1552·2021-11-17 09:33
閱讀 1100·2021-11-12 10:36
閱讀 2414·2019-08-30 15:54
閱讀 2441·2019-08-30 13:14
閱讀 2914·2019-08-26 14:05
閱讀 3289·2019-08-26 11:32
閱讀 3001·2019-08-26 10:09
閱讀 2995·2019-08-26 10:09