摘要:抽象工廠模式多個(gè)抽象產(chǎn)品類,個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類。用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從羅技換到微軟。好處避免頻繁創(chuàng)建對(duì)象,節(jié)省系統(tǒng)開銷,減輕壓力。
總體分為3大類:
創(chuàng)建型模式 (5種):工廠方法、抽象工廠、單例、建造者、原型
結(jié)構(gòu)型模式(7種):適配器、裝飾器、代理、外觀、橋接、組合、享元
行為型模式(11種):策略、模板方法、觀察者、迭代子、責(zé)任鏈、命令、備忘錄、狀態(tài)、訪問者、中介者、解釋器
其它(2種):并發(fā)型、線程池
開閉原則(總原則):對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉,需要使用接口和抽象類
單一職責(zé):每個(gè)類應(yīng)該實(shí)現(xiàn)單一的職責(zé)
里氏替換:基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。類似于向上轉(zhuǎn)型,子類對(duì)父類的方法盡量不要重寫和重載,會(huì)破壞父類定義好的與外界交互規(guī)范。是對(duì)開閉原則的補(bǔ)充,實(shí)現(xiàn)開閉原則的關(guān)鍵是抽象化,里氏替換原則是對(duì)實(shí)現(xiàn)抽象化規(guī)范
依賴倒轉(zhuǎn):面向接口編程,依賴于抽象,不依賴于具體。代碼中:不與具體類交互,與接口交互。開閉原則的基礎(chǔ)。
接口隔離:接口中的方法在子類中一定能用到,否則拆分成多個(gè)接口
迪米特法則(最少知道):對(duì)外暴露越少越好
合成復(fù)用:盡量使用合成/聚合的方式,而不是使用繼承
創(chuàng)建型模式(5種):工廠方法、抽象工廠、單例、建造者、原型。 一、工廠方法模式
創(chuàng)建1個(gè)接口、2個(gè)實(shí)現(xiàn)類
public interface Sender { void send(); }
public class MailSender implements Sender { @Override public void send() { System.out.println("this is mailsender!"); } }
public class SmsSender implements Sender { @Override public void send() { System.out.println("this is smssender!"); } }
創(chuàng)建1個(gè)工廠接口、2個(gè)工廠實(shí)現(xiàn)類
public interface Provider { Sender produce(); }
public class SendMailFactory implements Provider { @Override public Sender produce() { return new MailSender(); } }
public class SendSmsFactory implements Provider { @Override public Sender produce() { return new SmsSender(); } }
測(cè)試類
public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.send(); } }
如果想增加一個(gè)功能,則只需做一個(gè)實(shí)現(xiàn)類,實(shí)現(xiàn) Sender 接口,同時(shí)做一個(gè)工廠類,實(shí)現(xiàn) Provider 接口,就 OK 了,無需去改動(dòng)現(xiàn)成的代碼。這樣做,拓展性較好!
二、抽象工廠模式工廠方法模式和抽象工廠模式的區(qū)別如下:
工廠方法模式:
1個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類。
1個(gè)抽象工廠類可以派生出多個(gè)具體工廠類。1個(gè)具體工廠類只能創(chuàng)建1個(gè)具體產(chǎn)品類的實(shí)例。
抽象工廠模式:
多個(gè)抽象產(chǎn)品類,1個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類。
1個(gè)抽象工廠類可以派生出多個(gè)具體工廠類。1個(gè)具體工廠類可以創(chuàng)建多個(gè)具體產(chǎn)品類的實(shí)例,也就是創(chuàng)建的是一個(gè)產(chǎn)品線下的多個(gè)產(chǎn)品。
對(duì)于 java 來說,你能見到的大部分抽象工廠模式都是這樣的:
---它的里面是一堆工廠方法,每個(gè)工廠方法返回某種類型的對(duì)象。
比如說工廠可以生產(chǎn)鼠標(biāo)和鍵盤。那么抽象工廠的實(shí)現(xiàn)類(它的某個(gè)具體子類)的對(duì)象都可以生產(chǎn)鼠標(biāo)和鍵盤,但可能工廠 A 生產(chǎn)的是羅技的鍵盤和鼠標(biāo),工廠 B 是微軟的。
用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從羅技換到微軟。但是用了抽象工廠模式,你只要換家工廠,就可以同時(shí)替換鼠標(biāo)和鍵盤一套。如果你要的產(chǎn)品有幾十個(gè),當(dāng)然用抽象工廠模式一次替換全部最方便(這個(gè)工廠會(huì)替你用相應(yīng)的工廠方法)所以說抽象工廠就像工廠,而工廠方法則像是工廠的一種產(chǎn)品生產(chǎn)線
單例模式能保證在一個(gè)JVM中該對(duì)象只有一個(gè)實(shí)例存在。好處:
1、 避免頻繁創(chuàng)建對(duì)象,節(jié)省系統(tǒng)開銷,減輕 GC 壓力。
2、在系統(tǒng)中某些對(duì)象只能有一個(gè)(比如一個(gè)軍隊(duì)出現(xiàn)了多個(gè)司令員同時(shí)指揮,肯定會(huì)亂成一團(tuán))
簡(jiǎn)單的單例類(單線程):
只能在單線程中用,不能用于多線程。
public class Singleton { /* 持有私有靜態(tài)實(shí)例,防止被引用,此處賦值為 null,目的是實(shí)現(xiàn)延遲加載 */ private static Singleton instance = null; /* 私有構(gòu)造方法,防止被實(shí)例化 */ private Singleton() { } /* 靜態(tài)工程方法,創(chuàng)建實(shí)例 */ public static Singleton getInstance() { if (instance == null){ instance = new Singleton(); } return instance; } /* 如果該對(duì)象被用于序列化,可以保證對(duì)象在序列化前后保持一致 */ public Object readResolve(){ return instance; } }
同步代碼塊:
/* 靜態(tài)工程方法,創(chuàng)建實(shí)例 */ public static Singleton getInstance() { if (instance == null){ synchronized (instance){ if(instance == null){ instance = new Singleton(); } } } return instance; }
在 Java 指令中創(chuàng)建對(duì)象和賦值操作是分開進(jìn)行的,也就是說 instance = new Singleton();語句是分兩步執(zhí)行的,可能會(huì)先為Singleton實(shí)例分配空間,再賦值給instance,最后初始化Singleton實(shí)例。
A、B 兩個(gè)線程為例:
A、B 線程同時(shí)進(jìn)入了第一個(gè) if 判斷
A首先進(jìn)入 synchronized 塊,由于 instance 為 null,所以它執(zhí)行 instance = new Singleton();
由于 JVM 內(nèi)部的優(yōu)化機(jī)制,JVM 先畫出了一些分配給 Singleton 實(shí)例的空白內(nèi)存,并賦值給 instance 成員(注意此時(shí) JVM 沒有開始初始化這個(gè)實(shí)例),然后 A 離開了 synchronized塊。
B進(jìn)入 synchronized 塊,由于 instance 此時(shí)不是 null,因此它馬上離開了 synchronized 塊并將結(jié)果返回給調(diào)用該方法的程序。
此時(shí) B 線程打算使用 Singleton 實(shí)例,卻發(fā)現(xiàn)它沒有被初始化,于是錯(cuò)誤發(fā)生了。
上面這些話可以理解為A線程從同步代碼塊出來后,JVM沒有初始化Singleton實(shí)例,B線程調(diào)用instance時(shí)發(fā)現(xiàn)Singleton沒有初始化。
多線程單例
使用內(nèi)部類來維護(hù)單例的實(shí)現(xiàn),JVM 內(nèi)部的機(jī)制能夠保證當(dāng)一個(gè)類被加載的時(shí)候,這個(gè)類的加載過程是線程互斥的。這樣當(dāng)我們第一次調(diào)用 getInstance 的時(shí)候,JVM 能夠幫我們保證 instance 只被創(chuàng)建一次,并且會(huì)保證把賦值給 instance 的內(nèi)存初始化完畢,這樣我們就不用擔(dān)心上面的問題。同時(shí)該方法也只會(huì)在第一次調(diào)用的時(shí)候使用互斥機(jī)制,這樣就解決了低性能問題。
public class Singleton { /* 私有構(gòu)造方法,防止被實(shí)例化 */ private Singleton() { } /* 此處使用一個(gè)內(nèi)部類來維護(hù)單例 */ private static class SingletonFactory{ private static Singleton instance = new Singleton(); } /* 獲取實(shí)例 */ public static Singleton getInstance(){ return SingletonFactory.instance; } /* 如果該對(duì)象被用于序列化,可以保證對(duì)象在序列化前后保持一致 */ public Object readResolve(){ return getInstance(); } }
將創(chuàng)建和賦值分開,多帶帶為創(chuàng)建類加靜態(tài)同步方法
因?yàn)槲覀冎恍枰趧?chuàng)建類的時(shí)候進(jìn)行同步,所以只要將創(chuàng)建和getInstance()分開,多帶帶為創(chuàng)建加 synchronized 關(guān)鍵字,也是可以的
public class SingletonTest { private static SingletonTest instance = null; public SingletonTest() { } private static synchronized void syncInit(){ if(instance == null){ instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null){ syncInit(); } return instance; } }
補(bǔ)充:用 采用" 影子實(shí)例"的辦法為單例對(duì)象的屬性同步更新
public class SingletonTest { private static SingletonTest instance = null; private Vector properties = null; public Vector getProperties() { return properties; } public SingletonTest() { } private static synchronized void syncInit(){ if(instance == null){ instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null){ syncInit(); } return instance; } public void updateProperties(){ SingletonTest shadow = new SingletonTest(); properties = shadow.getProperties(); } }
類和靜態(tài)方法與靜態(tài)類區(qū)別:
靜態(tài)類不能實(shí)現(xiàn)接口。(從類的角度說是可以的,但是那樣就破壞了靜態(tài)了。因?yàn)榻涌谥胁辉试S有 static 修飾的方法,所以即使實(shí)現(xiàn)了也是非靜態(tài)的)
單例可以被延遲初始化,靜態(tài)類一般在第一次加載是初始化。之所以延遲加載,是因?yàn)橛行╊惐容^龐大,所以延遲加載有助于提升性能。
單例類可以被繼承,他的方法可以被覆寫。但是靜態(tài)類內(nèi)部方法都是 static,無法被覆寫。
四、建造者模式(Builder) 五、原型模式(Prototype)將一個(gè)對(duì)象作為原型,對(duì)其進(jìn)行復(fù)制、克隆后產(chǎn)生一個(gè)和原對(duì)象類似的新對(duì)象
淺復(fù)制:將一個(gè)對(duì)象復(fù)制后,基本數(shù)據(jù)類型的變量都會(huì)重新創(chuàng)建,而引用類型,指向的還是原對(duì)象所指向的。
深復(fù)制:將一個(gè)對(duì)象復(fù)制后,不論是基本數(shù)據(jù)類型還有引用類型,都是重新創(chuàng)建的。
一個(gè)原型類,只需要實(shí)現(xiàn) Cloneable 接口,覆寫 clone 方法,此處 clone 方法可以改成任意的名稱,因?yàn)?Cloneable 接口是個(gè)空接口,你可以任意定義實(shí)現(xiàn)類的方法名,如 cloneA或者cloneB,因?yàn)榇颂幍闹攸c(diǎn)是super.clone()這句話,super.clone()調(diào)用的是Object的clone()方法,而在 Object 類中,clone()是 native 的。這里寫一個(gè)深淺復(fù)制的例子
public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj; /*淺復(fù)制*/ public Object clone() throws CloneNotSupportedException{ Prototype proto = (Prototype)super.clone(); return proto; } /*深復(fù)制*/ public Object deepClone() throws IOException, ClassNotFoundException { /* 寫入當(dāng)前對(duì)象的二進(jìn)制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* 讀出二進(jìn)制流產(chǎn)生的新對(duì)象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this.string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this.obj = obj; } } class SerializableObject implements Serializable{ private static final long serialVersionUID = 1L; }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/71052.html
摘要:數(shù)據(jù)源內(nèi)嵌的數(shù)據(jù)庫,通過命令直接啟動(dòng)即可,無需額外安裝。參考資料部署手冊(cè)集群部署說明推薦閱讀系列歡迎來到的世界系列基于的注冊(cè)中心系列基于的配置中心系列的使用 三種部署模式 Nacos支持三種部署模式 1、單機(jī)模式:可用于測(cè)試和單機(jī)使用,生產(chǎn)環(huán)境切忌使用單機(jī)模式(滿足不了高可用) 2、集群模式:可用于生產(chǎn)環(huán)境,確保高可用 3、多集群模式:可用于多數(shù)據(jù)中心場(chǎng)景 單機(jī)模式 啟動(dòng) Nacos ...
摘要:前言設(shè)計(jì)模式是面向?qū)ο蟮淖罴褜?shí)踐實(shí)戰(zhàn)實(shí)戰(zhàn)創(chuàng)建型模式單例模式工廠模式抽象工廠模式原型模式建造者模式實(shí)戰(zhàn)結(jié)構(gòu)型模式橋接模式享元模式外觀模式適配器模式裝飾器模式組合模式代理模式過濾器模式實(shí)戰(zhàn)行為型模式模板模式策略模式狀態(tài)模式觀察者模式責(zé)任鏈模式訪 前言 設(shè)計(jì)模式是面向?qū)ο蟮淖罴褜?shí)踐 實(shí)戰(zhàn) PHP實(shí)戰(zhàn)創(chuàng)建型模式 單例模式 工廠模式 抽象工廠模式 原型模式 建造者模式 PHP實(shí)戰(zhàn)結(jié)構(gòu)型模式 ...
摘要:策略模式介紹策略模式定義了一系列的算法,并將每一個(gè)算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。使用策略模式的好處策略模式提供了管理相關(guān)的算法族的辦法。使用策略模式可以避免使用多重條件轉(zhuǎn)移語句。 你好,是我琉憶,PHP程序員面試筆試系列圖書的作者。 本周(2019.3.11至3.15)的一三五更新的文章如下: 周一:PHP面試??贾O(shè)計(jì)模式——工...
摘要:設(shè)計(jì)一個(gè)好的并非易事,本文先從設(shè)計(jì)時(shí)最容易犯的兩個(gè)錯(cuò)誤開始介紹,然后引出如何合理地設(shè)計(jì)。錯(cuò)誤以為設(shè)計(jì)的依據(jù)以為設(shè)計(jì)的依據(jù),往往是一個(gè)對(duì)應(yīng)一個(gè)子,的結(jié)構(gòu)同返回的數(shù)據(jù)結(jié)構(gòu)保持一致或接近一致。至此,的結(jié)構(gòu)設(shè)計(jì)完成。 Redux是一個(gè)非常流行的狀態(tài)管理解決方案,Redux應(yīng)用執(zhí)行過程中的任何一個(gè)時(shí)刻,都是一個(gè)狀態(tài)的反映??梢哉f,State 驅(qū)動(dòng)了Redux邏輯的運(yùn)轉(zhuǎn)。設(shè)計(jì)一個(gè)好的State并非...
摘要:一懶漢式線程不安全懶漢式線程不安全私有構(gòu)造方法只允許在內(nèi)部進(jìn)行實(shí)例的創(chuàng)建創(chuàng)建實(shí)例二懶漢式線程安全懶漢式線程安全私有構(gòu)造方法只允許在內(nèi)部進(jìn)行實(shí)例的創(chuàng)建創(chuàng)建實(shí)例線程安全三餓漢式線程安全餓漢式私有構(gòu)造方法只允許在內(nèi)部進(jìn)行實(shí)例的創(chuàng)建靜態(tài)初始化由保證 一、懶漢式(線程不安全) package com.java.singleton; //懶漢式 線程不安全 public class LazySi...
閱讀 2564·2023-04-25 19:24
閱讀 1791·2021-11-11 16:54
閱讀 2895·2021-11-08 13:19
閱讀 3619·2021-10-25 09:45
閱讀 2630·2021-09-13 10:24
閱讀 3395·2021-09-07 10:15
閱讀 4202·2021-09-07 10:14
閱讀 3025·2019-08-30 15:56