什么是設(shè)計(jì)模式?
設(shè)計(jì)模式是一套代碼設(shè)計(jì)「?經(jīng)驗(yàn)的總結(jié)?」。項(xiàng)目中「?合理的?」運(yùn)用設(shè)計(jì)模式可以「?巧妙的解決很多問(wèn)題?」。
經(jīng)驗(yàn)的總結(jié):抱著「代碼虐我千百遍,我待代碼如初戀」的心態(tài),最終得出來(lái)的「套路」。
合理的:要對(duì)設(shè)計(jì)模式的使用場(chǎng)景有一定的認(rèn)識(shí)后才使用,「不要濫用」。
巧妙的解決了很多問(wèn)題:被廣泛應(yīng)用的原因。
為什么要提倡“Design?Pattern呢?根本原因是為了代碼復(fù)用,增加可維護(hù)性。那么怎么才能實(shí)現(xiàn)代碼復(fù)用呢?
設(shè)計(jì)模式之六大原則
開閉原則(Open?Close?Principle)
1988年,勃蘭特·梅耶(Bertrand?Meyer)在他的著作《面向?qū)ο筌浖?gòu)造(Object?Oriented?Software?Construction)》中提出了開閉原則,它的原文是這樣:“Software?entities?should?be?open?for?extension,but?closed?for?modification”。
意思:軟件模塊應(yīng)該對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。
舉例:在程序需要進(jìn)行新增功能的時(shí)候,不能去修改原有的代碼,而是新增代碼,實(shí)現(xiàn)一個(gè)熱插拔的效果(熱插拔:靈活的去除或添加功能,不影響到原有的功能)。
目的:為了使程序的擴(kuò)展性好,易于維護(hù)和升級(jí)。
里氏代換原則(Liskov?Substitution?Principle)
意思:里氏代換原則是繼承復(fù)用的基石,只有當(dāng)衍生類可以替換掉基類,?軟件單位的功能不受到影響時(shí)?,基類才能真正被復(fù)用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。
舉例:球類,原本是一種體育用品,它的衍生類有籃球、足球、排球、羽毛球等等,如果衍生類替換了基類的原本方法,如把體育用品改成了食用品(那么軟件單位的功能受到影響),就不符合里氏代換原則。
目的:對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范。
依賴倒轉(zhuǎn)原則(Dependence?Inversion?Principle)
意思:針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程。
舉例:以計(jì)算機(jī)系統(tǒng)為例,無(wú)論主板、CPU、內(nèi)存、硬件都是在針對(duì)接口設(shè)計(jì)的,如果針對(duì)實(shí)現(xiàn)來(lái)設(shè)計(jì),內(nèi)存就要對(duì)應(yīng)到針對(duì)某個(gè)品牌的主板,那么會(huì)出現(xiàn)換內(nèi)存需要把主板也換掉的尷尬。
目的:降低模塊間的耦合。
接口隔離原則(Interface?Segregation?Principle)
使用多個(gè)隔離的接口,比使用單個(gè)接口要好。
舉例:比如:登錄,注冊(cè)時(shí)屬于用戶模塊的兩個(gè)接口,比寫成一個(gè)接口好。
目的:提高程序設(shè)計(jì)靈活性。
迪米特法則(最少知道原則)(Demeter?Principle)
1987年秋天由美國(guó)Northeastern?University的Ian?Holland提出,被UML的創(chuàng)始者之一[Booch]等普及。后來(lái),因?yàn)樵诮?jīng)典著作《The?Pragmatic?Programmer》而廣為人知。
意思:一個(gè)實(shí)體應(yīng)當(dāng)盡量少的與其他實(shí)體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立。
舉例:一個(gè)類公開的public屬性或方法越多,修改時(shí)涉及的面也就越大,變更引起的風(fēng)險(xiǎn)擴(kuò)散也就越大。
目的:降低類之間的耦合,減少對(duì)其他類的依賴。
單一職責(zé)原則(Single?responsibility?principle)
該原則由羅伯特·C·馬?。≧obert?C.?Martin)于《敏捷軟件開發(fā):原則、模式和實(shí)踐》一書中給出的。馬丁表示此原則是基于?湯姆·狄馬克(Tom?DeMarco)和Meilir?Page-Jones的著作中的?內(nèi)聚性?原則發(fā)展出的。
意思:一個(gè)類只負(fù)責(zé)一個(gè)功能領(lǐng)域中的相應(yīng)職責(zé),或者可以定義為:就一個(gè)類而言,應(yīng)該只有一個(gè)引起它變化的原因。
舉例:該原則意思簡(jiǎn)單到不需要舉例!
目的:類的復(fù)雜性降低,可讀性提高,可維護(hù)性提高。
剛?cè)胄械臅r(shí)候,在想什么樣的代碼是好代碼?看到很多前輩的文字都說(shuō)好的代碼要符合「高內(nèi)聚,低耦合」,但是我聽到這樣的解釋,是這樣的
而現(xiàn)在對(duì)設(shè)計(jì)模式有了一定程度上的學(xué)習(xí),感覺(jué)懂了一些,小伙伴們你們學(xué)會(huì)了嗎?
高內(nèi)聚,低耦合?
內(nèi)聚是從功能角度來(lái)度量模塊內(nèi)的聯(lián)系,一個(gè)好的內(nèi)聚模塊應(yīng)當(dāng)恰好做一件事。它描述的是模塊內(nèi)的功能聯(lián)系;
耦合是軟件結(jié)構(gòu)中各模塊之間相互連接的一種度量,耦合強(qiáng)弱取決于模塊間接口的復(fù)雜程度、進(jìn)入或訪問(wèn)一個(gè)模塊的點(diǎn)以及通過(guò)接口的數(shù)據(jù)。
創(chuàng)建模式
抽象工廠模式(Abstract?Factory)?,提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)需指定它們具體的類。
生成器模式(Builder),將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。
工廠方法模式(Factory?Method),定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定將哪一個(gè)類實(shí)例化。Factory?Method使一個(gè)類的實(shí)例化延遲到其子類。
原型模式(Prototype),用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過(guò)拷貝這個(gè)原型來(lái)創(chuàng)建新的對(duì)象。
單例模式(Singleton),保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。
結(jié)構(gòu)模式
適配器模式(Adapter),將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
橋接模式(Bridge),將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。
組合模式(Composite),將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。它使得客戶對(duì)單個(gè)對(duì)象和復(fù)合對(duì)象的使用具有一致性。
容器模式
修飾模式(Decorator),動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就擴(kuò)展功能而言,?它比生成子類方式更為靈活。
擴(kuò)展性模式
外觀模式
享元模式
管道與過(guò)濾器模式
代理模式(Proxy),為其他對(duì)象提供一個(gè)代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。
行為模式
責(zé)任鏈模式(Chain?of?Responsibility),為解除請(qǐng)求的發(fā)送者和接收者之間耦合,而使多個(gè)對(duì)象都有機(jī)會(huì)處理這個(gè)請(qǐng)求。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它。
命令模式(Command),將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可取消的操作。
柯里化模式
事件監(jiān)聽器模式
解釋器模式
迭代器模式
中介者模式
備忘錄模式(Memento),在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到保存的狀態(tài)。
觀察者模式(Observer),定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,以便當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并自動(dòng)刷新。
狀態(tài)模式(State),允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。對(duì)象看起來(lái)似乎修改了它所屬的類。
策略模式(Strategy),定義一系列的算法,把它們一個(gè)個(gè)封裝起來(lái),并且使它們可相互替換。本模式使得算法的變化可獨(dú)立于使用它的客戶。
模板方法模式
訪問(wèn)者模式(Visitor),表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
知道的也就:簡(jiǎn)單工廠模式,抽象工廠模式,單例模式,原型模式
說(shuō)下對(duì)單例模式的了解:
意圖:
保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。
適用性:
當(dāng)類只能有一個(gè)實(shí)例而且客戶可以從一個(gè)眾所周知的訪問(wèn)點(diǎn)訪問(wèn)它時(shí)。
當(dāng)這個(gè)唯一實(shí)例應(yīng)該是通過(guò)子類化可擴(kuò)展的,并且客戶應(yīng)該無(wú)需更改代碼就能使用一個(gè)擴(kuò)展的實(shí)例時(shí)。
單例模式(Singleton?Pattern):確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,這個(gè)類稱為單例類,它提供全局訪問(wèn)的方法。單例模式是一種對(duì)象創(chuàng)建型模式。
單例模式有三個(gè)要點(diǎn):一是某個(gè)類只能有一個(gè)實(shí)例;二是它必須自行創(chuàng)建這個(gè)實(shí)例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
單例模式是結(jié)構(gòu)最簡(jiǎn)單的設(shè)計(jì)模式一,在它的核心結(jié)構(gòu)中只包含一個(gè)被稱為單例類的特殊類。
這里寫圖片描述

單例模式結(jié)構(gòu)圖中只包含一個(gè)單例角色:
Singleton(單例):在單例類的內(nèi)部實(shí)現(xiàn)只生成一個(gè)實(shí)例,同時(shí)它提供一個(gè)靜態(tài)的getInstance()工廠方法,讓客戶可以訪問(wèn)它的唯一實(shí)例;為了防止在外部對(duì)其實(shí)例化,將其構(gòu)造函數(shù)設(shè)計(jì)為私有;在單例類內(nèi)部定義了一個(gè)Singleton類型的靜態(tài)對(duì)象,作為外部共享的唯一實(shí)例。
主要優(yōu)點(diǎn):
1、提供了對(duì)唯一實(shí)例的受控訪問(wèn)。
2、由于在系統(tǒng)內(nèi)存中只存在一個(gè)對(duì)象,因此可以節(jié)約系統(tǒng)資源,對(duì)于一些需要頻繁創(chuàng)建和銷毀的對(duì)象單例模式無(wú)疑可以提高系統(tǒng)的性能。
3、允許可變數(shù)目的實(shí)例。
主要缺點(diǎn):
1、由于單利模式中沒(méi)有抽象層,因此單例類的擴(kuò)展有很大的困難。
2、單例類的職責(zé)過(guò)重,在一定程度上違背了“單一職責(zé)原則”。
3、濫用單例將帶來(lái)一些負(fù)面問(wèn)題,如為了節(jié)省資源將數(shù)據(jù)庫(kù)連接池對(duì)象設(shè)計(jì)為的單例類,可能會(huì)導(dǎo)致共享連接池對(duì)象的程序過(guò)多而出現(xiàn)連接池溢出;如果實(shí)例化的對(duì)象長(zhǎng)時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為是垃圾而被回收,這將導(dǎo)致對(duì)象狀態(tài)的丟失。
適用場(chǎng)景
在以下情況下可以考慮使用單例模式:
-?(1)系統(tǒng)只需要一個(gè)實(shí)例對(duì)象,如系統(tǒng)要求提供一個(gè)唯一的序列號(hào)生成器或資源管理器,或者需要考慮資源消耗太大而只允許創(chuàng)建一個(gè)對(duì)象。
-?(2)客戶調(diào)用類的單個(gè)實(shí)例只允許使用一個(gè)公共訪問(wèn)點(diǎn),除了該公共訪問(wèn)點(diǎn),不能通過(guò)其他途徑訪問(wèn)該實(shí)例。
class?A:
__instance=None
__isfirst=True
def?__init__(self,name):
if?A.__isfirst:
self.name=name
A.__isfirst=False
def?__new__(*args,**kwargs):
if?args[0].__instance==None:
args[0].__instance=object.__new__(args[0])
return?args[0].__instance
a2=A('老板')
a1=A('laoban')
print(a1)
print(a2)
print(a2.name)
print(a1.name)