單例設計模式(singleton)最常用、最簡單的設計模式。單例模式的目的是保證在整個應用中某一個類有且只有一個實例(一個類在堆內存只存在一個對象)。怎么樣讓一個類一個類有且只有一個實例呢?最核心的就是一句話就是構造方法私有化。單例模式的編寫有很多種寫法。比如餓漢式、懶漢式、雙重加鎖機制靜態內部類、枚舉。
餓漢式,從名字上理解像是有個人很容易餓,所以他每次不管自己餓不餓,沒事就提前把要吃的東西先準備出來,也就是 “比較勤”,所以實例在初始化的時候就已經建好了,不管你有沒有用到,都先建好了再說。
[1] 構造方法私有化,防止外界通過構造器創建新的工具類對象;
[2] 必須在該類中,自己先創建出一個對象;
[3] 向外暴露一個公共的靜態方法用于返回自身的對象;
// 單例模式(餓漢式)
public class Singleton1 {
// [1]構造方法私有化,防止外界通過構造器創建新的工具類對象
private Singleton1() {
}
// [2] 必須在該類中,自己先創建出一個對象(這行代碼在類加載的時候就執行了)
private static Singleton1 instance = new Singleton1();
// [3] 向外暴露一個公共的靜態方法用于返回自身的對象
public static Singleton1 getSingleton() {
return instance;
}
}
注意:我們知道,類加載的方式是按需加載,且加載一次。因此,在上述單例類被加載時,就會實例化一個對象并交給自己的引用,供系統使用;而且,由于這個類在整個生命周期中只會被加載一次,因此只會創建一個實例,即能夠充分保證單例。
好處:這種寫法比較簡單,就是在類裝載的時候就完成實例化。避免了線程同步問題。
壞處:在類裝載的時候就完成實例化,沒有達到Lazy Loading(懶加載)的效果。 如果從始至終從未使用過這個實例,則會造成內存的浪費。
懶漢式,顧名思義就像一個人比較懶,平時不愛動,事情火燒眉毛了才迫不得已去做,“比較懶”,用的時候才去檢查有沒有實例,如果有則返回,沒有則新建。有線程安全和線程不安全兩種寫法,區別就是synchronized關鍵字。
[1] 構造方法私有化,防止外界通過構造器創建新的工具類對象
[2] 事先創建好當前類的一個私有靜態對象
[3] 向外暴露一個公共的靜態方法用于返回自身的對象
// 單例模式(懶漢式)
public class Singleton2 {
// [1]私有化構造方法。
private Singleton2() {
}
// [2] 事先創建好當前類的一個私有靜態對象
private static Singleton2 instance = null;
// [3] 向外暴露一個公共的靜態方法用于返回自身的對象
public static Singleton2 getInstance() {
// 被動創建,在真正需要使用時才去創建
if (null == instance) {
instance= new Singleton2();
}
return instance;
}
}
注意:我們從懶漢式單例可以看到,單例實例被延遲加載,即只有在真正使用的時候才會實例化一個對象并交給自己的引用。
優缺點:這種寫法起到了Lazy Loading(懶加載)的效果,但是只能在單線程下使用。如果在多線程下,一個線程進入了if (singleton == null)判斷語句塊,還未來得及往下執行,另一個線程也通過了這個判斷語句,這時便會產生多個實例。所以在多線程環境下不可使用這種方式。
為了解決上面的問題,最簡單的方法是將整個 getInstance() 方法設為同步(synchronized)。
// 單例模式(懶漢式)
public class Singleton2 {
// [1]私有化構造方法。
private Singleton2() {
}
// [2] 事先創建好當前類的一個私有靜態對象
private static Singleton2 instance = null;
// [3] 向外暴露一個公共的靜態方法用于返回自身的對象
public static synchronized Singleton2 getInstance() {
// 被動創建,在真正需要使用時才去創建
if (null == instance) {
instance= new Singleton2();
}
return instance;
}
}
注意:雖然做到了線程安全,并且解決了多實例的問題,但是它并不高效。因為同步操作只需要在第一次調用時才被需要,即第一次創建單例實例對象時,也就是if條件判斷里面的內容。這就引出了雙重檢驗鎖。
雙重檢驗鎖,又叫雙重校驗鎖,綜合了懶漢式和餓漢式兩者的優缺點整合而成。看上面代碼實現中,特點是在synchronized關鍵字內外都加了一層 if 條件判斷,這樣既保證了線程安全,又比直接上鎖提高了執行效率,還節省了內存空間。
// 單例模式(懶漢式)
public class Singleton3 {
private static Singleton3 instance;
private Singleton3 (){}
public static Singleton3 getSingleton() {
if (instance == null) {
synchronized (Singleton3.class) {
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
public class Singleton4 {
private static class SingletonHolder {
private static final Singleton4 INSTANCE = new Singleton4();
}
private Singleton4 (){}
public static final Singleton4 getInstance() {
return SingletonHolder.INSTANCE;
}
}
注意:這種寫法仍然使用JVM本身機制保證了線程安全問題;由于 SingletonHolder 是私有的,除了 getInstance() 之外沒有辦法訪問它,因此它是懶漢式的;同時讀取實例的時候不會進行同步,沒有性能缺陷;也不依賴 JDK 版本。
public enum EasySingleton{
// 定義枚舉常量
INSTANCE;
}
使用:我們可以通過EasySingleton.INSTANCE.工具方法() 的方式來訪問實例,這比調用getInstance()方法簡單多了。創建枚舉默認就是線程安全的,所以不需要擔心double checked locking,而且還能防止反序列化導致重新創建新的對象。
1)網站的計數器,一般也是采用單例模式實現,否則難以同步。
2)應用程序的日志應用,一般都是單例模式實現,只有一個實例去操作才好,否則內容不好追加顯示。
3)多線程的線程池的設計一般也是采用單例模式,因為線程池要方便對池中的線程進行控制
4)Windows的(任務管理器)就是很典型的單例模式,他不能打開倆個
5)windows的(回收站)也是典型的單例應用。在整個系統運行過程中,回收站只維護一個實例。
工廠模式提供了一種創建對象的最佳方式。在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,并且是通過使用一個共同的接口來指向新創建的對象。實現了創建者和調用者分離,工廠模式分為簡單工廠、工廠方法、抽象工廠模式。
簡單工廠模式又叫靜態方法模式(因為工廠類定義了一個靜態方法)現實生活中,工廠是負責生產產品的;同樣在設計模式中,簡單工廠模式我們可以理解為負責生產對象的一個類,稱為“工廠類”。
將“類實例化的操作”與“使用對象的操作”分開,讓使用者不用知道具體參數就可以實例化出所需要的“產品”類,從而避免了在客戶端代碼中顯式指定,實現了解耦。即使用者可直接消費產品而不需要知道其生產的細節
簡單工廠模式:把對象的創建放到一個工廠類中,通過參數來創建不同的對象。
/**
* 簡單工廠類
*/
public class SimpleFactory {
/**
* 生產工廠
*/
public static OSSConfig createOSSConfig(String name) {
OSSConfig config = null;
switch (name) {
case "alibaba":
config = new AlibabaOSSConfig();
break;
case "tencent":
config = new TencentOSSConfig();
break;
default:
break;
}
return config;
}
}
將創建實例的工作與使用實例的工作分開,使用者不必關心類對象如何創建,實現了解耦;
把初始化實例時的工作放到工廠里進行,使代碼更容易維護。 更符合面向對象的原則 & 面向接口編程,而不是面向實現編程。
1)工廠類集中了所有實例(產品)的創建邏輯,一旦這個工廠不能正常工作,整個系統都會受到影響;
2)違背“開放 - 關閉原則”,一旦添加新產品就不得不修改工廠類的邏輯,這樣就會造成工廠邏輯過于復雜。
3)簡單工廠模式由于使用了靜態工廠方法,靜態方法不能被繼承和重寫,會造成工廠角色無法形成基于繼承的等級結構。
客戶如果只知道傳入工廠類的參數,對于如何創建對象的邏輯不關心時;
當工廠類負責創建的對象(具體產品)比較少時。
工廠方法模式,又稱工廠模式、多態工廠模式和虛擬構造器模式,通過定義工廠父類負責定義創建對象的公共接口,而子類則負責生成具體的對象。
工廠方法模式: 每種產品由一種工廠來創建,一個工廠處理一個對象。
角色組成
1. 抽象工廠: 定義工廠類所具有的基本的操作
2. 具體工廠:該類必須繼承抽象工廠,實現抽象工廠定義的方法,返回一個對象
3. 抽象產品:定義了抽象產品具有的基本操作
4. 產品實現類:實現抽象產品類對定義的抽象方法,和具體工廠一一對應;
/**
* 抽象產品: 配置接口
*/
interface OSSConfig {
/**
* 初始化OSS配置
*/
void init();
}
/**
* 具體產品: 阿里云OSS配置
*/
class AlibabaOSSConfig implements OSSConfig {
@Override
public void init() {
System.out.println("初始化--阿里云--OSS配置");
}
}
/**
* 具體產品: 騰訊云OSS配置
*/
class TencentOSSConfig implements OSSConfig {
@Override
public void init() {
System.out.println("初始化--騰訊云--OSS配置");
}
}
/**
* 抽象工廠
*/
interface Factory {
OSSConfig createOSSConfig();
}
/**
* 具體工廠: 騰訊云工廠
*/
class TencentOSSFactory implements Factory {
@Override
public OSSConfig createOSSConfig() {
return new TencentOSSConfig();
}
}
/**
* 具體工廠: 阿里云工廠
*/
class AlibabaOSSFactory implements Factory {
@Override
public OSSConfig createOSSConfig() {
return new AlibabaOSSConfig();
}
}
/**
* 工廠設計模擬類
*/
public class FactoryMethod {
public static void main(String[] args) {
AlibabaOSSFactory alibabaOSSFactory = new AlibabaOSSFactory();
OSSConfig alibabaConifg = alibabaOSSFactory.createOSSConfig();
alibabaConifg.init();
TencentOSSFactory tencentOSSFactory = new TencentOSSFactory();
OSSConfig tencentConfig = tencentOSSFactory.createOSSConfig();
tencentConfig.init();
}
}
工廠方法模式把具體產品的創建推遲到工廠類的子類(具體工廠)中,此時工廠類不再負責所有產品的創建,而只是給出具體工廠必須實現的接口,這樣工廠方法模式在添加新產品的時候就不修改工廠類邏輯而是添加新的工廠子類,符合開放封閉原則,克服了簡單工廠模式中缺點。
1)更符合開-閉原則
新增一種產品時,只需要增加相應的具體產品類和相應的工廠子類即可
簡單工廠模式需要修改工廠類的判斷邏輯
2)符合單一職責原則
每個具體工廠類只負責創建對應的產品
簡單工廠中的工廠類存在復雜的switch邏輯判斷
3)不使用靜態工廠方法,可以形成基于繼承的等級結構。
簡單工廠模式的工廠類使用靜態工廠方法
總結:工廠模式可以說是簡單工廠模式的進一步抽象和拓展,在保留了簡單工廠的封裝優點的同時,讓擴展變得簡單,讓繼承變得可行,增加了多態性的體現。
1)添加新產品時,除了增加新產品類外,還要提供與之對應的具體工廠類,系統類的個數將成對增加,在一定程度上增加了系統的復雜度;同時,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷;
2)由于考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度。
3)雖然保證了工廠方法內的對修改關閉,但對于使用工廠方法的類,如果要更換另外一種產品,仍然需要修改實例化的具體工廠類;一個具體工廠只能創建一種具體產品。
1)當一個類不知道它所需要的對象的類時,在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可;
2)當一個類希望通過其子類來指定創建對象時,在工廠方法模式中,對于抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
3)將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
抽象工廠模式,即Abstract Factory Pattern,提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類;具體的工廠負責實現具體的產品實例。 允許使用抽象的接口來創建一組相關產品,而不需要知道或關心實際生產出的具體產品是什么,這樣就可以從具體產品中被解耦。
抽象工廠模式:工廠方法模式的進一步延伸。
角色組成
1. 抽象工廠: 定義工廠類所具有的基本的操作
2. 具體工廠:具體工廠實現了抽象工廠,每個工廠方法返回多個具體對象
3. 抽象類接口:定義了產品具有的基本操作,提供一組所有類都具有的業務方法
4. 抽象類:用于實現抽象接口所定義的業務方法,只做抽象接口,具體由產品實現類處理
5. 產品實現類:實現抽象產品類對定義的抽象方法,和具體工廠一對多;
/**
* 抽象產品: 配置接口
*/
interface OSSConfig {
/**
* 初始化OSS配置
*/
void init();
}
/**
* 具體產品: 阿里云OSS配置
*/
abstract class AlibabaOSSConfig implements OSSConfig {
public abstract void init();
}
/**
* 具體產品: 阿里云OSS配置Test環境
*/
class AlibabaTstOSSConfig extends AlibabaOSSConfig {
@Override
public void init() {
System.out.println("初始化--阿里云--test環境--OSS配置");
}
}
/**
* 具體產品: 阿里云OSS配置生產環境
*/
class AlibabaPreOSSConfig extends AlibabaOSSConfig {
@Override
public void init() {
System.out.println("初始化--阿里云--Pre環境--OSS配置");
}
}
/**
* 抽象產品: 騰訊云OSS配置
*/
abstract class TencentOSSConfig implements OSSConfig {
public abstract void init();
}
/**
* 抽象產品: 騰訊云OSS配置
*/
class TencentProOSSConfig extends TencentOSSConfig {
@Override
public void init() {
System.out.println("初始化--騰訊云--Pre環境--OSS配置");
}
}
/**
* 抽象工廠
*/
interface Factory {
/**
* 獲取測試環境配置
*/
OSSConfig createOSSTestConfig();
/**
* 獲取生成環境配置
*/
OSSConfig createOSSPreConfig();
}
/**
* 具體工廠: 騰訊云工廠
*/
class TencentOSSFactory implements Factory {
@Override
public OSSConfig createOSSTestConfig() {
return null;
}
@Override
public OSSConfig createOSSPreConfig() {
return new TencentProOSSConfig();
}
}
/**
* 具體工廠: 騰訊云工廠
*/
class AlibabaOSSFactory implements Factory {
@Override
public OSSConfig createOSSTestConfig() {
return new AlibabaTstOSSConfig();
}
@Override
public OSSConfig createOSSPreConfig() {
return new AlibabaPreOSSConfig();
}
}
/**
* 工廠設計模擬類
* 產品接口可以定義OSS配置的操作接口,不同的廠商實現都去實現接口,通過工廠動態生成配置
*/
public class AbstractFactory {
public static void main(String[] args) {
// 阿里云oss配置
AlibabaOSSFactory alibabaOSSFactory = new AlibabaOSSFactory();
OSSConfig alibabaConifg = alibabaOSSFactory.createOSSPreConfig();
alibabaConifg.init();
OSSConfig alibabaTestConifg = alibabaOSSFactory.createOSSTestConfig();
alibabaTestConifg.init();
// 騰云云oss配置
TencentOSSFactory tencentOSSFactory = new TencentOSSFactory();
OSSConfig tencentConifg = tencentOSSFactory.createOSSPreConfig();
tencentConifg.init();
}
}
1)降低耦合
抽象工廠模式將具體產品的創建延遲到具體工廠的子類中,這樣將對象的創建封裝起來,可以減少客戶端與具體產品類之間的依賴,從而使系統耦合度低,這樣更有利于后期的維護和擴展;
2)更符合開-閉原則
新增一種產品類時,只需要增加相應的具體產品類和相應的工廠子類即可
3)符合單一職責原則
每個具體工廠類只負責創建對應的產品
4)不使用靜態工廠方法,可以形成基于繼承的等級結構。
抽象工廠模式很難支持新種類產品的變化。這是因為抽象工廠接口中已經確定了可以被創建的產品集合,如果需要添加新產品,此時就必須去修改抽象工廠的接口,這樣就涉及到抽象工廠類的以及所有子類的改變,這樣也就違背了“開發——封閉”原則。
1)一個系統不要求依賴產品類實例如何被創建、組合和表達的表達,這點也是所有工廠模式應用的前提。
2)這個系統有多個系列產品,而系統中只消費其中某一系列產品
3)系統要求提供一個產品類的庫,所有產品以同樣的接口出現,客戶端不需要依賴具體實現。
工廠方法模式:具體工廠類只能創建一個具體產品類的實例。
抽象工廠模式:具體工廠類可以創建多個具體產品類的實例。
給目標對象提供一個代理對象,并由代理對象控制對目標對象的引用。其中代理對象起到中介作用,用于連接客戶端和目標對象。例如:電腦桌面的快捷方式。電腦對某個程序提供一個快捷方式(代理對象),快捷方式連接客戶端和程序,客戶端通過操作快捷方式就可以操作那個程序。
通過引入代理對象的方式來間接訪問目標對象,防止直接訪問目標對象給系統帶來的不必要復雜性。
步驟1: 創建抽象對象接口(Subject):聲明你(真實對象)需要讓代購(代理對象)幫忙做的事(買Mac)
public interface Subject { ?
public void buyMac();
}
步驟2: 創建真實對象類(RealSubject),即”我“
public class RealSubject implement Subject{
? ?@Override
? public void buyMac() { ?
? ? ? System.out.println(”買一臺Mac“); ?
? } ?
}
步驟3:創建代理對象類(Proxy),即”代購“,并通過代理類創建真實對象實例并訪問其方法
public class Proxy ?implements Subject{
??
? ?@Override
? public void buyMac{ ??
? ? //引用并創建真實對象實例,即”我“
? ? RealSubject realSubject = new RealSubject();
? ? //調用真實對象的方法,進行代理購買Mac
? ? realSubject.buyMac();
? ? //代理對象額外做的操作
? ? this.WrapMac();
? }
? ?public void WrapMac(){
? ? System.out.println(”用盒子包裝好Mac“); ?
? }
}
步驟4:客戶端調用
public class ProxyPattern {
? ? public static void main(String[] args){
? ? Subject proxy = new Proxy();
? ? proxy.buyMac();
? ? }? ? ??
}
結果輸出
買一臺Mac
用盒子包裝好Mac
優點
協調調用者和被調用者,降低了系統的耦合度
代理對象作為客戶端和目標對象之間的中介,起到了保護目標對象的作用
缺點
由于在客戶端和真實主題之間增加了代理對象,因此會造成請求的處理速度變慢;
實現代理模式需要額外的工作(有些代理模式的實現非常復雜),從而增加了系統實現的復雜度。
在靜態代理模式中一個靜態代理只服務一種類型的目標對象,若要服務多類型的目標對象,則需要為每種目標對象都實現一個靜態代理對象。在目標對象較多的情況下,若采用靜態代理,則會出現 靜態代理對象量多、代碼量大,從而導致代碼復雜的問題。
動態代理就是,在程序運行期,創建目標對象的代理對象,并對目標對象中的方法進行功能性增強的一種技術。在生成代理對象的過程中,目標對象不變,代理對象中的方法是目標對象方法的增強方法。可以理解為運行期間,對象中方法的動態攔截,在攔截方法的前后執行功能操作。
代理類在程序運行期間,創建的代理對象稱之為動態代理對象。這種情況下,創建的代理對象,并不是事先在Java代碼中定義好的。而是在運行期間,根據我們在動態代理對象中的“指示”,動態生成的。也就是說,你想獲取哪個對象的代理,動態代理就會為你動態的生成這個對象的代理對象。動態代理可以對被代理對象的方法進行功能增強。有了動態代理的技術,那么就可以在不修改方法源碼的情況下,增強被代理對象的方法的功能,在方法執行前后做任何你想做的事情。
1)動態代理不需要顯式實現與目標對象類(RealSubject)相同的接口,而是將這種實現推遲到程序運行時由 JVM來實現。即:在使用時再創建動態代理類 & 實例;
2)通過Java 反射機制的method.invoke(),通過調用動態代理類對象方法,從而自動調用目標對象的方法。
優點
1)只需要1個動態代理類就可以解決創建多個靜態代理的問題,避免重復、多余代碼;
2)更強的靈活性;
缺點
1)效率低:相比靜態代理中直接調用目標對象方法,動態代理則需要先通過Java反射機制 從而間接調用目標對象方法。
2)應用場景局限:Java 的單繼承特性(每個代理類都繼承了 Proxy 類),即只能針對接口創建代理類,不能針對類創建代理類。
日志記錄、性能統計、安全控制、異常處理等。
1.創建接口,定義目標類需要完成的功能
2.創建目標類,實現接口。
3.創建InvocationHandler接口的實現類。在invoke方法中完成代理類的功能。
目標方法的調用
功能增強
4.使用Proxy類中靜態方法Proxy.newProxyInstance完成代理類對象的創建,返回代理對象,并把返回值轉為接口類型。
public class JDKDynamicProxy {
public static void main(String[] args) {
CAProxy caProxy = new CAProxy();
IA instance = (IA) caProxy.getInstance(new CA());
instance.say();
instance.fly();
}
}
interface IA{
void say();
void fly();
}
class CA implements IA{
@Override
public void say() {
System.out.println("I am class CA");
}
@Override
public void fly() {
System.out.println("I can fly");
}
}
class CAProxy implements InvocationHandler{
private Object target;
public Object getInstance(Object object){
this.target = object;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("I am proxy!");
Object result = method.invoke(target, args);
return result;
}
}
public class CglibDynamicProxy {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
A a = (A) cglibProxy.getInstance(new A());
a.say();
}
}
class A {
public void say(){
System.out.println("I am A");
}
}
class CglibProxy implements MethodInterceptor{
private Object target;
public Object getInstance(Object object){
this.target = object;
Enhancer enhancer = new Enhancer();
// 設置父類為實例類
enhancer.setSuperclass(this.target.getClass());
// 回調方法
enhancer.setCallback(this);
// 創建代理對象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("I am cglib proxy!");
Object result = method.invoke(target, objects);
return result;
}
}
設計模式(Design pattern)是一種思想,是一套被反復使用的代碼設計經驗總結,專門用于解決特定場景的需求。它提供了在軟件開發過程中面臨的一些問題的最佳解決方案,使用設計模式是為了提高代碼的可重用性、讓代碼通俗易懂,增加代碼可靠性。
開閉原則:對擴展開放,對修改關閉。就是如果要修改原有的功能或者是擴展功能,盡量去擴展原有的代碼,而不是修改原來已有的代碼。
里氏替換原則:任何子類對象都應該可以替換其派生的超類對象 。即,子類可以擴展父類的功能,但不要修改父類原有的功能。 也就是說,當一個子類繼承父類后,盡量不要去重寫它原有的方法。
依賴轉置(依賴倒置)原則:要面向接口編程,不要面向實現編程。兩個模塊交互時,都訪問各自接口,而不是具體的實現類。
單一職責原則:一個對象要專注于一種事情,不要讓它擔任太多責任。
接口隔離原則:一個接口盡量只包含用戶關心的內容。就是一個接口不要太龐大。
迪米特法則:如果兩個軟件實體之間不是特別必要,盡量不要讓他們直接通信。而是找個第三方進行轉發,比如使用MQ(消息隊列)。
合成復用原則:如果在“組合/聚合”和“繼承”之間做抉擇時,優先選擇“組合/聚合”。
創建型模式:用于創建對象的設計模式。一般可以簡化用戶創建對象的過程。其次可以降低耦合度,用戶不需要關心對象具體的創建過程。包含:單例模式、原型模型、工廠模式、建造者模式。
結構型模型:組織對象之間的結構。使其易于擴展等。包括:代理模式、適配器模式、橋接模式、裝飾器模式、外觀模式、享元模式、組合模式。
行為模型:主要用于決定對象如何做出行為包括:模板方法模式、策略模式、命令模式、責任鏈、狀態模式、觀察者模式、中介者模式、迭代器模式、訪問者模式、備忘錄模式、解釋器模式。
1)提高代碼復用率,降低開發成本和周期;
2)提高代碼可維護性、可拓展性;
3)使代碼更加優雅、更容易被他人理解。
開閉原則要求你的代碼對擴展開放,對修改關閉。這個意思就是說,如果你想增加一個新的功 能,你可以很容易的在不改變已測試過的代碼的前提下增加新的代碼。有好幾個設計模式是基 于開閉原則的,如策略模式,如果你需要一個新的策略,只需要實現接口,增加配置,不需要 改變核心邏輯。一個正在工作的例子是 Collections.sort() 方法,這就是基于策略模式,遵循 開閉原則的,你不需為新的對象修改 sort() 方法,你需要做的僅僅是實現你自己的 Comparator 接口。
如果兩個對象彼此有關系,就說他們是彼此相關聯的。組合和聚合是面向對象中的兩種形式的 關聯。組合是一種比聚合更強力的關聯。組合中,一個對象是另一個的擁有者,而聚合則是指 一個對象使用另一個對象。如果對象 A 是由對象 B 組合的,則 A 不存在的話,B一定不存在, 但是如果 A 對象聚合了一個對象 B,則即使 A 不存在了,B 也可以單獨存在。