面向對象設計的設計模式(一):建立型模式(附 Demo & UML類圖)

繼上一篇的面向對象設計的設計原則,本篇是面向對象設計系列的第二個部分:面向對象設計的設計模式的第一篇文章。html

最開始說一下什麼是設計模式。關於設計模式的概念,有不少不一樣的版本,在這裏說一下我我的比較贊同的一個說法:前端

設計模式用於在特定的條件下爲一些重複出現的軟件設計問題提供合理的、有效的解決方案。java

去掉一些定語的修飾,這句話精簡爲:git

設計模式爲問題提供方案。github

簡單來看,設計模式其實就是針對某些問題的一些方案。在軟件開發中,即便不少人在用不一樣的語言去開發不一樣的業務,可是不少時候這些人遇到的問題抽象出來都是類似的。一些卓越的開發者將一些常出現的問題和對應的解決方案彙總起來,總結出了這些設計模式。算法

所以掌握了這些設計模式,可讓咱們更好地去解決開發過程當中遇到的一些常見問題。並且對這些問題的解決方案的掌握程度越好,咱們就越可以打破語言自己的限制去解決問題,也就是加強「軟件開發的內功」。sql

介紹設計模式最著名的一本書莫屬《設計模式 可複用面向對象軟件的基礎》這本書,書中共介紹了23個設計模式。而這些設計模式分爲三大類:數據庫

  • 建立型設計模式:側重於對象的建立。
  • 結構型設計模式:側重於接口的設計和系統的結構。
  • 行爲型設計模式:側重於類或對象的行爲。

而本篇做爲該系列的第一篇,講解的是設計模式中的6個建立型設計模式:編程

  1. 簡單工廠模式(Simple Factory Pattern)
  2. 工廠方法模式(Factory Method Pattern)
  3. 抽象工廠模式(Abstract Factory Pattern)
  4. 單例模式(Singleton Pattern)
  5. 生成器模式(Builder Pattern)
  6. 原型模式(Prototype Pattern)

注意:簡單工廠模式不是 GoF總結出來的23種設計模式之一,不存在於《設計模式 可複用面向對象軟件的基礎》這本書中。設計模式

在面向對象設計中,類與對象幾乎是構成全部系統的基本元素,所以我認爲學好了建立型模式纔是學會設計系統的第一步:由於你應該知道如何去建立一些特定性質的對象,這纔是設計好的系統的開始。

在講解這6個設計模式以前先說一下該系列文章的講解方式:

從更多維度來理解一件事物有助於更深入地理解它,所以每一個設計模式我都會從如下這幾點來說解:

  • 定義
  • 使用場景
  • 成員與類圖
  • 代碼示例
  • 優勢
  • 缺點
  • iOS SDK 和 JDK 中的應用

最後一項:「iOS SDK 和 JDK中的應用」講解的是該設計模式在Objective-C和java語言(JDK)中的應用。

首先咱們看一下簡單工廠模式:

一. 簡單工廠模式

定義

簡單工廠模式(Simple Factory Pattern):專門定義一個類(工廠類)來負責建立其餘類的實例。能夠根據建立方法的參數來返回不一樣類的實例,被建立的實例一般都具備共同的父類。

簡單工廠模式又稱爲靜態工廠方法(Static Factory Method)模式,它屬於類建立型模式。

適用場景

若是咱們但願將一些爲數很少的相似的對象的建立和他們的建立細節分離開,也不須要知道對象的具體類型,可使用簡單工廠模式。

舉個形象點的例子:在前端開發中,經常會使用外觀各式各樣的按鈕:好比有的按鈕有圓角,有的按鈕有陰影,有的按鈕有邊框,有的按鈕無邊框等等。可是由於同一種樣式的按鈕能夠出如今項目的不少地方,因此若是在每一個地方都把建立按鈕的邏輯寫一遍的話顯然是會形成代碼的重複(並且因爲業務的緣由有的按鈕的建立邏輯能比較複雜,代碼量大)。

那麼爲了不重複代碼的產生,咱們能夠將這些建立按鈕的邏輯都放在一個「工廠」裏面,讓這個工廠來根據你的需求(傳入的參數)來建立對應的按鈕並返回給你。這樣一來,一樣類型的按鈕在多個地方使用的時候,就能夠只給這個工廠傳入其對應的參數並拿到返回的按鈕便可。

下面來看一下簡單工廠模式的成員和類圖。

成員與類圖

成員

簡單工廠模式的結構比較簡單,一共只有三個成員:

  • 工廠(Factory):工廠負責實現建立全部產品實例的邏輯
  • 抽象產品(Product):抽象產品是工廠所建立的全部產品對象的父類,負責聲明全部產品實例所共有的公共接口。
  • 具體產品(Concrete Product):具體產品是工廠所建立的全部產品對象類,它以本身的方式來實現其共同父類聲明的接口。

下面經過類圖來看一下各個成員之間的關係:

模式類圖

簡單工廠模式類圖

從類圖中能夠看出,工廠類提供一個靜態方法:經過傳入的字符串來製造其所對應的產品。

代碼示例

場景概述

舉一個店鋪售賣不一樣品牌手機的例子:店鋪,即客戶端類向手機工廠購進手機售賣。

場景分析

該場景可使用簡單工廠的角色來設計:

  • 抽象產品:Phone,是全部具體產品類的父類,提供一個公共接口packaging表示手機的裝箱並送到店鋪。
  • 具體產品:不一樣品牌的手機,iPhone手機類(IPhone),小米手機類(MIPhone),華爲手機類(HWPhone)。
  • 工廠:PhoneFactory根據不一樣的參數來建立不一樣的手機。
  • 客戶端類:店鋪類Store負責售賣手機。

代碼實現

抽象產品類Phone

//================== Phone.h ==================
@interface Phone : NSObject

//package to store
- (void)packaging;

@end
複製代碼

具體產品類 IPhone

//================== IPhone.h ==================
@interface IPhone : Phone

@end


//================== IPhone.m ==================
@implementation IPhone

- (void)packaging{
    NSLog(@"IPhone has been packaged");
}

@end
複製代碼

具體產品類 MIPhone

//================== MIPhone.h ==================
@interface MIPhone : Phone

@end



//================== MIPhone.m ==================
@implementation MIPhone

- (void)packaging{
    NSLog(@"MIPhone has been packaged");
}

@end
複製代碼

具體產品類:HWPhone:

//================== HWPhone.h ==================
@interface HWPhone : Phone

@end



//================== HWPhone.m ==================
@implementation HWPhone

- (void)packaging{
    NSLog(@"HUAWEI Phone has been packaged");
}

@end
複製代碼

以上是抽象產品類以及它的三個子類:蘋果手機類,小米手機類和華爲手機類。 下面看一下工廠類 PhoneFactory

//================== PhoneFactory.h ==================
@interface PhoneFactory : NSObject

+ (Phone *)createPhoneWithTag:(NSString *)tag;

@end


//================== PhoneFactory.m ==================
#import "IPhone.h"
#import "MIPhone.h"
#import "HWPhone.h"

@implementation PhoneFactory

+ (Phone *)createPhoneWithTag:(NSString *)tag{
    
    if ([tag isEqualToString:@"i"]) {
        
        IPhone *iphone = [[IPhone alloc] init];
        return iphone;
        
    }else if ([tag isEqualToString:@"MI"]){
        
        MIPhone *miPhone = [[MIPhone alloc] init];
        return miPhone;
        
    }else if ([tag isEqualToString:@"HW"]){
        
        HWPhone *hwPhone = [[HWPhone alloc] init];
        return hwPhone;
        
    }else{
        
        return nil;
    }
}

@end
複製代碼

工廠類向外部(客戶端)提供了一個創造手機的接口createPhoneWithTag:,根據傳入參數的不一樣能夠返回不一樣的具體產品類。所以客戶端只須要知道它所須要的產品所對應的參數便可得到對應的產品了

在本例中,咱們聲明瞭店鋪類 Store爲客戶端類:

//================== Store.h ==================
#import "Phone.h"

@interface Store : NSObject

- (void)sellPhone:(Phone *)phone;

@end


//================== Store.m ==================
@implementation Store

- (void)sellPhone:(Phone *)phone{
    NSLog(@"Store begins to sell phone:%@",[phone class]);
}

@end
複製代碼

客戶端類聲明瞭一個售賣手機的接口sellPhone:。表示它能夠售賣做爲參數所傳入的手機。

最後咱們用代碼模擬一下這個實際場景:

//================== Using by client ==================


//1. A phone store wants to sell iPhone
Store *phoneStore = [[Store alloc] init];
    
//2. create phone
Phone *iPhone = [PhoneFactory  createPhoneWithTag:@"i"];
    
//3. package phone to store
[iphone packaging];
    
//4. store sells phone after receving it
[phoneStore sellPhone:iphone];
複製代碼

上面代碼的解讀:

  1. 最開始實例化一個商店,商店打算賣蘋果手機
  2. 商店委託工廠給他製做一臺iPhone手機,傳入對應的字段i
  3. 手機生產好之後打包送到商店
  4. 商店售賣手機

在這裏咱們須要注意的是:商店從工廠拿到手機不須要了解手機制做的過程,只須要知道它要工廠作的是手機(只知道Phone類便可),和須要給工廠類傳入它所需手機所對應的參數便可(這裏的iPhone手機對應的參數就是i)。

下面咱們看一下該例子對應的 UML類圖,能夠更直觀地看一下各個成員之間的關係:

代碼對應的類圖

簡單工廠模式代碼示例類圖

優勢

  • 客戶端只須要給工廠類傳入一個正確的(約定好的)參數,就能夠獲取你所須要的對象,而不須要知道其建立細節,必定程度上減小系統的耦合。
  • 客戶端無須知道所建立的具體產品類的類名,只須要知道具體產品類所對應的參數便可,減小開發者的記憶成本。

缺點

  • 若是業務上添加新產品的話,就須要修改工廠類原有的判斷邏輯,這實際上是違背了開閉原則的。
  • 在產品類型較多時,有可能形成工廠邏輯過於複雜。因此簡單工廠模式比較適合產品種類比較少並且增多的機率很低的狀況。

iOS SDK 和 JDK 中的應用

  • Objective-C中的類簇就是簡單工廠設計模式的一個應用。若是給NSNumber的工廠方法傳入不一樣類型的數據,則會返回不一樣數據所對應的NSNumber的子類。
  • JDK中的Calendar類中的私有的createCalendar(TimeZone zone, Locale aLocale)方法經過不一樣的入參來返回不一樣類型的Calendar子類的實例。

二. 工廠方法模式

定義

工廠方法模式(Factory Method Pattern)又稱爲工廠模式,工廠父類負責定義建立產品對象的公共接口,而工廠子類則負責生成具體的產品對象,即經過不一樣的工廠子類來建立不一樣的產品對象。

適用場景

工廠方法模式的適用場景與簡單工廠相似,都是建立數據和行爲比較相似的對象。可是和簡單工廠不一樣的是:在工廠方法模式中,由於建立對象的責任移交給了抽象工廠的子類,所以客戶端須要知道其所需產品所對應的工廠子類,而不是簡單工廠中的參數。

下面咱們看一下工廠方法模式的成員和類圖。

成員與類圖

成員

工廠方法模式包含四個成員:

  1. 抽象工廠(Abstract Factory):抽象工廠負責聲明具體工廠的建立產品的接口。
  2. 具體工廠(Concrete Factory):具體工廠負責建立產品。
  3. 抽象產品(Abstract Product):抽象產品是工廠所建立的全部產品對象的父類,負責聲明全部產品實例所共有的公共接口。
  4. 具體產品(Concrete Product):具體產品是工廠所建立的全部產品對象類,它以本身的方式來實現其共同父類聲明的接口。

下面經過類圖來看一下各個成員之間的關係:

模式類圖

工廠方法模式類圖

從類圖中咱們能夠看到:抽象工廠負責定義具體工廠必須實現的接口,而建立產品對象的任務則交給具體工廠,由特定的子工廠來建立其對應的產品。

這使得工廠方法模式能夠容許系統在不修改原有工廠的狀況下引進新產品:只須要建立新產品類和其所對應的工廠類便可。

代碼示例

場景概述

一樣也是模擬上面的簡單工廠例子中的場景(手機商店賣手機),可是因爲此次是由工廠方法模式來實現的,所以在代碼設計上會有變化。

場景分析

與簡單工廠模式不一樣的是:簡單工廠模式裏面只有一個工廠,而工廠方法模式裏面有一個抽象工廠和繼承於它的具體工廠。

所以一樣的三個品牌的手機,咱們能夠經過三個不一樣的具體工廠:蘋果手機工廠(IPhoneFactory),小米手機工廠 (MIPhoneFactory),華爲手機工廠(HWPhoneFactory)來生產。而這些具體工廠類都會繼承於抽象手機工廠類:PhoneFactory,它來聲明生產手機的接口。

下面咱們用代碼來具體來看一下工廠類(抽象工廠和具體工廠)的設計:

代碼實現

首先咱們聲明一個抽象工廠類 PhoneFactory

//================== PhoneFactory.h ==================
#import "Phone.h"

@interface PhoneFactory : NSObject

+ (Phone *)createPhone;

@end


//================== PhoneFactory.m ==================
@implementation PhoneFactory

+ (Phone *)createPhone{
    //implemented by subclass
    return nil;
}

@end
複製代碼

抽象工廠類給具體工廠提供了生產手機的接口,所以不一樣的具體工廠能夠按照本身的方式來生產手機。下面看一下具體工廠:

蘋果手機工廠 IPhoneFactory

//================== IPhoneFactory.h ==================
@interface IPhoneFactory : PhoneFactory
@end


//================== IPhoneFactory.m ==================
#import "IPhone.h"

@implementation IPhoneFactory

+ (Phone *)createPhone{
    
    IPhone *iphone = [[IPhone alloc] init];
    NSLog(@"iPhone has been created");
    return iphone;
}

@end
複製代碼

小米手機工廠 MIPhoneFactory

//================== MIPhoneFactory.h ==================
@interface MPhoneFactory : PhoneFactory

@end



//================== MIPhoneFactory.m ==================
#import "MiPhone.h"

@implementation MPhoneFactory

+ (Phone *)createPhone{
    
    MiPhone *miPhone = [[MiPhone alloc] init];
    NSLog(@"MIPhone has been created");
    return miPhone;
}

@end
複製代碼

華爲手機工廠 HWPhoneFactory:

//================== HWPhoneFactory.h ==================
@interface HWPhoneFactory : PhoneFactory

@end



//================== HWPhoneFactory.m ==================
#import "HWPhone.h"

@implementation HWPhoneFactory

+ (Phone *)createPhone{
    
    HWPhone *hwPhone = [[HWPhone alloc] init];
    NSLog(@"HWPhone has been created");
    return hwPhone;
}

@end
複製代碼

以上就是聲明的抽象工廠類和具體工廠類。由於生產手機的責任分配給了各個具體工廠類,所以客戶端只須要委託所需手機所對應的工廠就能夠得到其生產的手機了。

由於抽象產品類Phone和三個具體產品類(IPhoneMIPhoneHWPhone)和簡單工廠模式中介紹的例子中的同樣,所以這裏就再也不重複介紹了。

下面咱們用代碼模擬一下該場景:

//================== Using by client ==================


//A phone store
Store *phoneStore = [[Store alloc] init];
    
//phoneStore wants to sell iphone
Phone *iphone = [IPhoneFactory  createPhone];
[iphone packaging];
[phoneStore sellPhone:iphone];
    
    
//phoneStore wants to sell MIPhone
Phone *miPhone = [MPhoneFactory createPhone];
[miPhone packaging];
[phoneStore sellPhone:miPhone];
    
//phoneStore wants to sell HWPhone
Phone *hwPhone = [HWPhoneFactory createPhone];
[hwPhone packaging];
[phoneStore sellPhone:hwPhone];
複製代碼

由上面的代碼能夠看出:客戶端phoneStore只需委託iPhone,MIPhone,HWPhone對應的工廠便可得到對應的手機了。

並且之後若是增長其餘牌子的手機,例如魅族手機,就能夠聲明一個魅族手機類和魅族手機的工廠類並實現createPhone這個方法便可,而不須要改動原有已經聲明好的各個手機類和具體工廠類。

下面咱們看一下該例子對應的 UML類圖,能夠更直觀地看一下各個成員之間的關係:

代碼對應的類圖

工廠方法模式代碼示例類圖

優勢

  • 用戶只須要關心其所需產品對應的具體工廠是哪個便可,不須要關心產品的建立細節,也不須要知道具體產品類的類名。
  • 當系統中加入新產品時,不須要修改抽象工廠和抽象產品提供的接口,也無須修改客戶端和其餘的具體工廠和具體產品,而只要添加一個具體工廠和與其對應的具體產品就能夠了,符合了開閉原則(這一點與簡單工廠模式不一樣)。

缺點

  • 當系統中加入新產品時,除了須要提供新的產品類以外,還要提供與其對應的具體工廠類。所以系統中類的個數將成對增長,增長了系統的複雜度。

iOS SDK 和 JDK 中的應用

  • 暫未發現iOS SDK中使用工廠方法的例子,有知道的小夥伴歡迎留言。
  • 在JDK中,Collection接口聲明瞭iterator()方法,該方法返回結果的抽象類是IteratorArrayList就實現了這個接口;,而ArrayList對應的具體產品是Itr

三. 抽象工廠模式

定義

抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或相互依賴對象的接口,而無須指定它們具體的類。

適用場景

有時候咱們須要一個工廠能夠提供多個產品對象,而不是單一的產品對象。好比系統中有多於一個的產品族,而每次只使用其中某一產品族,屬於同一個產品族的產品將在一塊兒使用。

在這裏說一下產品族和產品等級結構的概念:

  • 產品族:同一工廠生產的不一樣產品
  • 產品等級結構:同一類型產品的不一樣實現

用一張圖來幫助理解:

在上圖中:

  • 縱向的,不一樣形狀,相同色系的圖形屬於同一產品組的產品,而同一產品族的產品對應的是同一個工廠;
  • 橫向的,同一形狀,不一樣色系的圖形屬於統一產品等級結構的產品,而統一產品等級結構的產品對應的是同一個工廠方法。

下面再舉一個例子幫助你們理解:

咱們將小米,華爲,蘋果公司比做抽象工廠方法裏的工廠:這三個工廠都有本身生產的手機,平板和電腦。 那麼小米手機,小米平板,小米電腦就屬於小米這個工廠的產品族;一樣適用於華爲工廠和蘋果工廠。 而小米手機,華爲手機,蘋果手機則屬於同一產品等級結構:手機的產品等級結構;平板和電腦也是如此。

結合這個例子對上面的圖作一個修改能夠更形象地理解抽象工廠方法的設計:

上面的關於產品族和產品等級結構的說法參考了慕課網實戰課程:java設計模式精講 Debug 方式+內存分析的6-1節。

成員與類圖

成員

抽象工廠模式的成員和工廠方法模式的成員是同樣的,只不過抽象工廠方法裏的工廠是面向產品族的。

  1. 抽象工廠(Abstract Factory):抽象工廠負責聲明具體工廠的建立產品族內的全部產品的接口。
  2. 具體工廠(Concrete Factory):具體工廠負責建立產品族內的產品。
  3. 抽象產品(Abstract Product):抽象產品是工廠所建立的全部產品對象的父類,負責聲明全部產品實例所共有的公共接口。
  4. 具體產品(Concrete Product):具體產品是工廠所建立的全部產品對象類,它以本身的方式來實現其共同父類聲明的接口。

下面經過類圖來看一下各個成員之間的關係:

模式類圖

抽象工廠模式類圖

  • 抽象工廠模式與工廠方法模式最大的區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則須要面對多個產品等級結構
  • 增長新的具體工廠和產品族很方便,無須修改已有系統,符合「開閉原則」。

代碼示例

場景概述

因爲抽象工廠方法裏的工廠是面向產品族的,因此爲了貼合抽象工廠方法的特色,咱們將上面的場景作一下調整:在上面兩個例子中,商店只賣手機。在這個例子中咱們讓商店也賣電腦:分別是蘋果電腦,小米電腦,華爲電腦。

場景分析

若是咱們仍是套用上面介紹過的工廠方法模式來實現該場景的話,則須要建立三個電腦產品對應的工廠:蘋果電腦工廠,小米電腦工廠,華爲電腦工廠。這就致使類的個數直線上升,之後若是還增長其餘的產品,還須要添加其對應的工廠類,這顯然是不夠優雅的。

仔細看一下這六個產品的特色,咱們能夠把這它們劃分在三個產品族裏面:

  1. 蘋果產品族:蘋果手機,蘋果電腦
  2. 小米產品族:小米手機,小米電腦
  3. 華爲產品族:華爲手機,華爲電腦

而抽象方法偏偏是面向產品族設計的,所以該場景適合使用的是抽象工廠方法。下面結合代碼來看一下該如何設計。

代碼實現

首先引入電腦的基類和各個品牌的電腦類:

電腦基類:

//================== Computer.h ==================
@interface Computer : NSObject

//package to store
- (void)packaging;

@end



//================== Computer.m ==================
@implementation Computer

- (void)packaging{
    //implemented by subclass
}

@end
複製代碼

蘋果電腦類 MacBookComputer

//================== MacBookComputer.h ==================
@interface MacBookComputer : Computer

@end



//================== MacBookComputer.m ==================
@implementation MacBookComputer

- (void)packaging{
     NSLog(@"MacBookComputer has been packaged");
}

@end
複製代碼

小米電腦類 MIComputer

//================== MIComputer.h ==================
@interface MIComputer : Computer

@end



//================== MIComputer.m ==================
@implementation MIComputer

- (void)packaging{
    NSLog(@"MIComputer has been packaged");
}

@end
複製代碼

華爲電腦類 MateBookComputer

//================== MateBookComputer.h ==================
@interface MateBookComputer : Computer

@end



//================== MateBookComputer.m ==================
@implementation MateBookComputer

- (void)packaging{
    NSLog(@"MateBookComputer has been packaged");
}

@end
複製代碼

引入電腦相關產品類之後,咱們須要從新設計工廠類。由於抽象工廠方法模式的工廠是面向產品族的,因此抽象工廠方法模式裏的工廠所建立的是同一產品族的產品。下面咱們看一下抽象工廠方法模式的工廠該如何設計:

首先建立全部工廠都須要集成的抽象工廠,它聲明瞭生產同一產品族的全部產品的接口:

//================== Factory.h ==================
#import "Phone.h"
#import "Computer.h"

@interface Factory : NSObject

+ (Phone *)createPhone;

+ (Computer *)createComputer;

@end



//================== Factory.m ==================
@implementation Factory

+ (Phone *)createPhone{
    
    //implemented by subclass
    return nil;
}

+ (Computer *)createComputer{
    
    //implemented by subclass
    return nil;
}

@end
複製代碼

接着,根據不一樣的產品族,咱們建立不一樣的具體工廠:

首先是蘋果產品族工廠 AppleFactory

//================== AppleFactory.h ==================
@interface AppleFactory : Factory

@end



//================== AppleFactory.m ==================
#import "IPhone.h"
#import "MacBookComputer.h"

@implementation AppleFactory

+ (Phone *)createPhone{
    
    IPhone *iPhone = [[IPhone alloc] init];
    NSLog(@"iPhone has been created");
    return iPhone;
}

+ (Computer *)createComputer{
    
    MacBookComputer *macbook = [[MacBookComputer alloc] init];
    NSLog(@"Macbook has been created");
    return macbook;
}

@end
複製代碼

接着是小米產品族工廠 MIFactory

//================== MIFactory.h ==================
@interface MIFactory : Factory

@end



//================== MIFactory.m ==================
#import "MIPhone.h"
#import "MIComputer.h"

@implementation MIFactory

+ (Phone *)createPhone{
    
    MIPhone *miPhone = [[MIPhone alloc] init];
    NSLog(@"MIPhone has been created");
    return miPhone;
}

+ (Computer *)createComputer{
    
    MIComputer *miComputer = [[MIComputer alloc] init];
    NSLog(@"MIComputer has been created");
    return miComputer;
}

@end
複製代碼

最後是華爲產品族工廠 HWFactory

//================== HWFactory.h ==================
@interface HWFactory : Factory

@end



//================== HWFactory.m ==================
#import "HWPhone.h"
#import "MateBookComputer.h"

@implementation HWFactory

+ (Phone *)createPhone{
    
    HWPhone *hwPhone = [[HWPhone alloc] init];
    NSLog(@"HWPhone has been created");
    return hwPhone;
}

+ (Computer *)createComputer{
    
    MateBookComputer *hwComputer = [[MateBookComputer alloc] init];
    NSLog(@"HWComputer has been created");
    return hwComputer;
}

@end
複製代碼

以上就是工廠類的設計。這樣設計好以後,客戶端若是須要哪一產品族的某個產品的話,只須要找到對應產品族工廠後,調用生產該產品的接口便可。假如須要蘋果電腦,只須要委託蘋果工廠來製造蘋果電腦便可;若是須要小米手機,只須要委託小米工廠製造小米手機便可。

下面用代碼來模擬一下這個場景:

//================== Using by client ==================


Store *store = [[Store alloc] init];
    
//Store wants to sell MacBook
Computer *macBook = [AppleFactory createComputer];
[macBook packaging];
    
[store sellComputer:macBook];
    
    
//Store wants to sell MIPhone
Phone *miPhone = [MIFactory createPhone];
[miPhone packaging];
    
[store sellPhone:miPhone];
    
    
//Store wants to sell MateBook
Computer *mateBook = [HWFactory createComputer];
[mateBook packaging];
    
[store sellComputer:mateBook];
複製代碼

上面的代碼就是模擬了商店售賣蘋果電腦,小米手機,華爲電腦的場景。而從此若是該商店引入了新品牌的產品,好比聯想手機,聯想電腦,那麼咱們只須要新增聯想手機類,聯想電腦類,聯想工廠類便可。

下面咱們看一下該例子對應的 UML類圖,能夠更直觀地看一下各個成員之間的關係:

代碼對應的類圖

抽象工廠模式代碼示例類圖

因爲三個工廠的產品總數過多,所以在這裏只體現了蘋果工廠和小米工廠的產品。

優勢

  • 具體產品在應用層代碼隔離,不須要關心產品細節。只須要知道本身須要的產品是屬於哪一個工廠的便可 當一個產品族中的多個對象被設計成一塊兒工做時,它可以保證客戶端始終只使用同一個產品族中的對象。這對一些須要根據當前環境來決定其行爲的軟件系統來講,是一種很是實用的設計模式。

缺點

  • 規定了全部可能被建立的產品集合,產品族中擴展新的產品困難,須要修改抽象工廠的接口。
  • 新增產品等級比較困難
  • 產品等級固定,而產品族不固定,擴展性強的場景。

iOS SDK 和 JDK 中的應用

  • 暫未發現iOS SDK中使用抽象工廠方法的例子,有知道的小夥伴歡迎留言。
  • JDK中有一個數據庫鏈接的接口Connection。在這個接口裏面有createStatement()prepareStatement(String sql)。這兩個接口都是獲取的統一產品族的對象,好比MySql和PostgreSQL產品族,具體返回的是哪一個產品族對象,取決於所鏈接的數據庫類型。

OK,到如今三個工廠模式已經講完了。在繼續講解下面三個設計模式以前,先簡單回顧一下上面講解的三個工廠模式:

大致上看,簡單工廠模式,工廠方法模式和抽象工廠模式的複雜程度是逐漸升高的。

  • 簡單工廠模式使用不一樣的入參來讓同一個工廠生產出不一樣的產品。
  • 工廠方法模式和抽象工廠模式都須要有特定的工廠類來生產對應的產品;而工廠方法模式裏的工廠是面向同一產品等級的產品;而抽象工廠方法模式裏的工廠是面向同一產品族的產品的。

在實際開發過程當中,咱們須要根據業務場景的複雜程度的不一樣來採用最適合的工廠模式。

四. 單例模式

定義

單例模式(Singleton Pattern):單例模式確保某一個類只有一個實例,並提供一個訪問它的全劇訪問點。

適用場景

系統只須要一個實例對象,客戶調用類的單個實例只容許使用一個公共訪問點,除了該公共訪問點,不能經過其餘途徑訪問該實例。比較典型的例子是音樂播放器,日誌系統類等等。

成員與類圖

成員

單例模式只有一個成員,就是單例類。由於只有一個成員,因此該設計模式的類圖比較簡單:

模式類圖

單例模式類圖

通常來講單例類會給外部提供一個獲取單例對象的方法,內部會用靜態對象的方式保存這個對象。

代碼示例

場景概述

在這裏咱們建立一個簡單的打印日至或上報日至的日至管理單例。

場景分析

在建立單例時,除了要保證提供惟一實例對象之外,還需注意多線程的問題。下面用代碼來看一下。

代碼實現

建立單例類 LogManager

//================== LogManager.h ==================
@interface LogManager : NSObject

+(instancetype)sharedInstance;

- (void)printLog:(NSString *)logMessage;

- (void)uploadLog:(NSString *)logMessage;

@end



//================== LogManager.m ==================
@implementation LogManager

static LogManager* _sharedInstance = nil;

+(instancetype)sharedInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[super allocWithZone:NULL] init] ;
    }) ;
    return _sharedInstance ;
}

+(id)allocWithZone:(struct _NSZone *)zone
{
    return [LogManager sharedInstance] ;
}

-(id)copyWithZone:(struct _NSZone *)zone
{
    return [LogManager sharedInstance];
}

-(id)mutableCopyWithZone:(NSZone *)zone
{
    return [LogManager sharedInstance];
}

- (void)printLog:(NSString *)logMessage{
    //print logMessage
}

- (void)uploadLog:(NSString *)logMessage{
    //upload logMessage
}

@end
複製代碼

從上面的代碼中能夠看到:

  • sharedInstance方法是向外部提供的獲取惟一的實例對象的方法,也是該類中的其餘能夠建立對象的方法的都調用的方法。在這個方法內部使用了dispatch_once函數來避免多線程訪問致使建立多個實例的狀況。
  • 爲了在alloc init出初始化方法能夠返回同一個實例對象,在allocWithZone:方法裏面仍然調用了sharedInstance方法。
  • 並且爲了在copymutableCopy方法也能夠返回同一個實例對象,在copyWithZone:mutableCopyWithZone也是調用了sharedInstance方法。

下面分別用這些接口來驗證一下實例的惟一性:

//================== Using by client ==================

//alloc&init
LogManager *manager0 = [[LogManager alloc] init];

//sharedInstance
LogManager *manager1 = [LogManager sharedInstance];

//copy
LogManager *manager2 = [manager0 copy];
    
//mutableCopy
LogManager *manager3 = [manager1 mutableCopy];
    
NSLog(@"\nalloc&init: %p\nsharedInstance: %p\ncopy: %p\nmutableCopy: %p",manager0,manager1,manager2,manager3);
複製代碼

咱們看一下打印出來的四個指針所指向對象的地址:

alloc&init:     0x60000000f7e0
sharedInstance: 0x60000000f7e0
copy:           0x60000000f7e0
mutableCopy:    0x60000000f7e0
複製代碼

能夠看出打印出來的地址都相同,說明都是同一對象,證實了實現方法的正確性。

下面咱們看一下該例子對應的 UML類圖,能夠更直觀地看一下各個成員之間的關係:

代碼對應的類圖

單例模式代碼示例類圖

優勢

  • 提供了對惟一實例的受控訪問。由於單例類封裝了它的惟一實例,因此它能夠嚴格控制客戶怎樣以及什麼時候訪問它。
  • 由於該類在系統內存中只存在一個對象,因此能夠節約系統資源。

缺點

  • 因爲單例模式中沒有抽象層,所以單例類很難進行擴展。
  • 對於有垃圾回收系統的語言(Java,C#)來講,若是對象長時間不被利用,則可能會被回收。那麼若是這個單例持有一些數據的話,在回收後從新實例化時就不復存在了。

iOS SDK 和 JDK 中的應用

  • 在Objective-C語言中使用單例模式的類有NSUserDefaults(key-value持久化)和UIApplication類(表明應用程序,能夠處理一些點擊事件等)。
  • 在JDK中使用的單例模式的類有Runtime類(表明應用程序的運行環境,使應用程序可以與其運行的環境相鏈接);Desktop類(容許 Java 應用程序啓動已在本機桌面上註冊的關聯應用程序)

五. 生成器模式

定義

生成器模式(Builder Pattern):也叫建立者模式,它將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。

具體點說就是:有些對象的建立流程是同樣的,可是由於自身特性的不一樣,因此在建立他們的時候須要將建立過程和特性的定製分離開來。

下面咱們看一下該設計模式的適用場景。

適用場景

當建立複雜對象的算法應該獨立於該對象的組成部分以及它們的裝配方式時比較適合使用生成器模式。

一些複雜的對象,它們擁有多個組成部分(如汽車,它包括車輪、方向盤、發送機等各類部件)。而對於大多數用戶而言,無須知道這些部件的裝配細節,也幾乎不會使用單獨某個部件,而是使用一輛完整的汽車。並且這些部分的建立順序是固定的,或者是須要指定的。

在這種狀況下能夠經過建造者模式對其進行設計與描述,生成器模式能夠將部件和其組裝過程分開,一步一步建立一個複雜的對象。

成員與類圖

成員

建造者模式包含4個成員:

  1. 抽象建造者(Builder):定義構造產品的幾個公共方法。
  2. 具體建造者(ConcreteBuilder):根據不一樣的需求來實現抽象建造者定義的公共方法;每個具體建造者都包含一個產品對象做爲它的成員變量。
  3. 指揮者(Director):根據傳入的具體建造者來返回其所對應的產品對象。
  4. 產品角色(Product):建立的產品。

下面經過類圖來看一下各個成員之間的關係:

模式類圖

生成器模式類圖

須要注意的是:

  • Builder類中的product成員變量的關鍵字爲protected,目的是爲了僅讓它和它的子類能夠訪問該成員變量。
  • Director類中的constructProductWithBuilder(Builder builder)方法是經過傳入不一樣的builder來構造產品的。並且它的getProduct()方法同時也封裝了Concrete Builder類的getProduct()方法,目的是爲了讓客戶端直接從Director拿到對應的產品(有些資料裏面的Director類沒有封裝Concrete Builder類的getProduct()方法)。

代碼示例

場景概述

模擬一個製造手機的場景:手機的組裝須要幾個固定的零件:CPU,RAM,屏幕,攝像頭,並且須要CPU -> RAM ->屏幕 -> 攝像頭的順序來製造。

場景分析

咱們使用建造者設計模式來實現這個場景:首先不一樣的手機要匹配不一樣的builder;而後在Director類裏面來定義製造順序。

代碼實現

首先咱們定義手機這個類,它有幾個屬性:

//================== Phone.h ==================
@interface Phone : NSObject

@property (nonatomic, copy) NSString *cpu;
@property (nonatomic, copy) NSString *capacity;
@property (nonatomic, copy) NSString *display;
@property (nonatomic, copy) NSString *camera;

@end
複製代碼

而後咱們建立抽象builder類:

//================== Builder.h ==================
#import "Phone.h"

@interface Builder : NSObject
{
    @protected Phone *_phone;
}

- (void)createPhone;

- (void)buildCPU;
- (void)buildCapacity;
- (void)buildDisplay;
- (void)buildCamera;


- (Phone *)obtainPhone;

@end
複製代碼

抽象builder類聲明瞭建立手機各個組件的接口,也提供了返回手機實例的對象。

接下來咱們建立對應不一樣手機的具體生成者類:

IPhoneXR手機的builder:IPhoneXRBuilder

//================== IPhoneXRBuilder.h ==================
@interface IPhoneXRBuilder : Builder

@end



//================== IPhoneXRBuilder.m ==================
@implementation IPhoneXRBuilder


- (void)createPhone{
    
    _phone = [[Phone alloc] init];
}


- (void)buildCPU{
    
    [_phone setCpu:@"A12"];
}

- (void)buildCapacity{

    [_phone setCapacity:@"256"];
}


- (void)buildDisplay{
    
    [_phone setDisplay:@"6.1"];
}

- (void)buildCamera{
    
    [_phone setCamera:@"12MP"];
}

- (Phone *)obtainPhone{
    return _phone;
}

@end
複製代碼

小米8手機的builder:MI8Builder

//================== MI8Builder.h ==================
@interface MI8Builder : Builder

@end



//================== MI8Builder.m ==================
@implementation MI8Builder

- (void)createPhone{
    
    _phone = [[Phone alloc] init];
}


- (void)buildCPU{
    
    [_phone setCpu:@"Snapdragon 845"];
}

- (void)buildCapacity{
    
    [_phone setCapacity:@"128"];
}


- (void)buildDisplay{
    
    [_phone setDisplay:@"6.21"];
}

- (void)buildCamera{
    
    [_phone setCamera:@"12MP"];
}

- (Phone *)obtainPhone{
    return _phone;
}

@end
複製代碼

從上面兩個具體builder的代碼能夠看出,這兩個builder都按照其對應的手機配置來建立其對應的手機。

下面來看一下Director的用法:

//================== Director.h ==================
#import "Builder.h"

@interface Director : NSObject

- (void)constructPhoneWithBuilder:(Builder *)builder;

- (Phone *)obtainPhone;

@end


//================== Director.m ==================
implementation Director
{
    Builder *_builder;
}


- (void)constructPhoneWithBuilder:(Builder *)builder{
    
    _builder = builder;
    
    [_builder buildCPU];
    [_builder buildCapacity];
    [_builder buildDisplay];
    [_builder buildCamera];
    
}


- (Phone *)obtainPhone{
    
    return [_builder obtainPhone];
}


@end

複製代碼

Director類提供了construct:方法,須要傳入builder的實例。該方法裏面按照既定的順序來建立手機。

最後咱們看一下客戶端是如何使用具體的Builder和Director實例的:

//================== Using by client ==================


//Get iPhoneXR
//1. A director instance
Director *director = [[Director alloc] init];
    
//2. A builder instance
IPhoneXRBuilder *iphoneXRBuilder = [[IPhoneXRBuilder alloc] init];
    
//3. Construct phone by director
[director construct:iphoneXRBuilder];
    
//4. Get phone by builder
Phone *iPhoneXR = [iphoneXRBuilder obtainPhone];
NSLog(@"Get new phone iPhoneXR of data: %@",iPhoneXR);
    
    
//Get MI8
MI8Builder *mi8Builder = [[MI8Builder alloc] init];
[director construct:mi8Builder];
Phone *mi8 = [mi8Builder obtainPhone];
NSLog(@"Get new phone MI8 of data: %@",mi8);
複製代碼

從上面能夠看出客戶端獲取具體產品的過程:

  1. 首先須要實例化一個Director的實例。
  2. 而後根據所須要的產品找出其對應的builder。
  3. 將builder傳入director實例的construct:方法。
  4. 從builder的obtainPhone獲取手機實例。

下面咱們看一下該例子對應的 UML類圖,能夠更直觀地看一下各個成員之間的關係:

代碼對應的類圖

生成器模式代碼示例類圖

優勢

  • 客戶端沒必要知道產品內部組成的細節,將產品自己與產品的建立過程解耦,使得相同的建立過程能夠建立不一樣的產品對象。
  • 每個具體建造者都相對獨立,而與其餘的具體建造者無關,所以能夠很方便地替換具體建造者或增長新的具體建造者, 用戶使用不一樣的具體建造者便可獲得不一樣的產品對象 。
  • 增長新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統擴展方便,符合「開閉原則」。
  • 能夠更加精細地控制產品的建立過程 。將複雜產品的建立步驟分解在不一樣的方法中,使得建立過程更加清晰,也更方便使用程序來控制建立過程。

缺點

  • 建造者模式所建立的產品通常具備較多的共同點,其組成部分類似,若是產品之間的差別性很大,則不適合使用建造者模式,所以其使用範圍受到必定的限制。

  • 若是產品的內部變化複雜,可能會致使須要定義不少具體建造者類來實現這種變化,致使系統變得很龐大。

iOS SDK 和 JDK 中的應用

  • 暫未發現iOS SDK中使用生成器設計模式的例子,有知道的小夥伴歡迎留言。
  • JDK中的StringBuilder屬於builder,它向外部提供append(String)方法來拼接字符串(也能夠傳入int等其餘類型);而toString()方法來返回字符串。

六. 原型模式

定義

原型模式(Prototype Pattern): 使用原型實例指定待建立對象的類型,而且經過複製這個原型來建立新的對象。

適用場景

  • 對象層級嵌套比較多,從零到一建立對象的過程比較繁瑣時,能夠直接經過複製的方式建立新的對象

  • 當一個類的實例只能有幾個不一樣狀態組合中的一種時,咱們能夠利用已有的對象進行復制來得到

成員與類圖

成員

原型模式主要包含以下兩個角色:

  1. 抽象原型類(Prototype):抽象原型類聲明克隆自身的接口。
  2. 具體原型類(ConcretePrototype):具體原型類實現克隆的具體操做(克隆數據,狀態等)。

下面經過類圖來看一下各個成員之間的關係:

模式類圖

原型模式類圖

須要注意的是,這裏面的clone()方法返回的是被複製出來的實例對象。

代碼示例

場景概述

模擬一份校招的簡歷,簡歷裏面有人名,性別,年齡以及學歷相關的信息。這裏面學歷相關的信息又包含學校名稱,專業,開始和截止年限的信息。

場景分析

這裏的學歷相關信息可使用單獨一個對象來作,所以總體的簡歷對象的結構能夠是:

簡歷對象:

  • 人名
  • 性別
  • 年齡
  • 學歷對象
    • 學校名稱
    • 專業
    • 開始年份
    • 結束年份

並且由於對於同一學校同一屆的同一專業的畢業生來講,學歷對象中的信息是相同的,這時候若是須要大量生成這些畢業生的簡歷的話比較適合使用原型模式。

代碼實現

首先定義學歷對象:

//================== UniversityInfo.h ==================
@interface UniversityInfo : NSObject<NSCopying>

@property (nonatomic, copy) NSString *universityName;
@property (nonatomic, copy) NSString *startYear;
@property (nonatomic, copy) NSString *endYear;
@property (nonatomic, copy) NSString *major;

- (id)copyWithZone:(NSZone *)zone;

@end



//================== UniversityInfo.m ==================
@implementation UniversityInfo

- (id)copyWithZone:(NSZone *)zone
{
    UniversityInfo *infoCopy = [[[self class] allocWithZone:zone] init];
    
    [infoCopy setUniversityName:[_universityName mutableCopy]];
    [infoCopy setStartYear:[_startYear mutableCopy]];
    [infoCopy setEndYear:[_endYear mutableCopy]];
    [infoCopy setMajor:[_major mutableCopy]];
   
    return infoCopy;
}

@end
複製代碼

由於學歷對象是支持複製的,所以須要聽從<NSCopying>協議並實現copyWithZone:方法。並且支持的是深複製,因此在複製NSString的過程當中須要使用mutableCopy來實現。

接着咱們看一下簡歷對象:

//================== Resume.h ==================
#import "UniversityInfo.h"

@interface Resume : NSObject<NSCopying>

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *gender;
@property (nonatomic, copy) NSString *age;

@property (nonatomic, strong) UniversityInfo *universityInfo;

@end



//================== Resume.m ==================
@implementation Resume

- (id)copyWithZone:(NSZone *)zone
{
    Resume *resumeCopy = [[[self class] allocWithZone:zone] init];
    
    [resumeCopy setName:[_name mutableCopy]];
    [resumeCopy setGender:[_gender mutableCopy]];
    [resumeCopy setAge:[_age mutableCopy]];
    [resumeCopy setUniversityInfo:[_universityInfo copy]];
    
    return resumeCopy;
}

@end
複製代碼

一樣地,簡歷對象也須要聽從<NSCopying>協議並實現copyWithZone:方法。

最後咱們看一下複製的效果有沒有達到咱們的預期(被複制對象和複製對象的地址和它們全部的屬性對象的地址都不相同)

//================== Using by client ==================


//resume for LiLei
Resume *resume = [[Resume alloc] init];
resume.name = @"LiLei";
resume.gender = @"male";
resume.age = @"24";
    
UniversityInfo *info = [[UniversityInfo alloc] init];
info.universityName = @"X";
info.startYear = @"2014";
info.endYear = @"2018";
info.major = @"CS";
    
resume.universityInfo = info;
    
    
//resume_copy for HanMeiMei
Resume *resume_copy = [resume copy];
    
NSLog(@"\n\n\n======== original resume ======== %@\n\n\n======== copy resume ======== %@",resume,resume_copy);
    
resume_copy.name = @"HanMeiMei";
resume_copy.gender = @"female";
resume_copy.universityInfo.major = @"TeleCommunication";
    
NSLog(@"\n\n\n======== original resume ======== %@\n\n\n======== revised copy resume ======== %@",resume,resume_copy);
複製代碼

上面的代碼模擬了這樣一個場景:李雷同窗寫了一份本身的簡歷,而後韓梅梅複製了一份並修改了姓名,性別和專業這三個和李雷不一樣的信息。

這裏咱們重寫了Resumedescription方法來看一下全部屬性的值及其內存地址。最後來看一下resume對象和resume_copy對象打印的結果:

//================== Output log ==================

======== original resume ======== 
resume object address:0x604000247d10
name:LiLei | 0x10bc0c0b0
gender:male | 0x10bc0c0d0
age:24 | 0x10bc0c0f0
university name:X| 0x10bc0c110
university start year:2014 | 0x10bc0c130
university end year:2018 | 0x10bc0c150
university major:CS | 0x10bc0c170


======== copy resume ======== 
resume object address:0x604000247da0
name:LiLei | 0xa000069654c694c5
gender:male | 0xa000000656c616d4
age:24 | 0xa000000000034322
university name:X| 0xa000000000000581
university start year:2014 | 0xa000000343130324
university end year:2018 | 0xa000000383130324
university major:CS | 0xa000000000053432





======== original resume ======== 
resume object address:0x604000247d10
name:LiLei | 0x10bc0c0b0
gender:male | 0x10bc0c0d0
age:24 | 0x10bc0c0f0
university name:X| 0x10bc0c110
university start year:2014 | 0x10bc0c130
university end year:2018 | 0x10bc0c150
university major:CS | 0x10bc0c170


======== revised copy resume ======== 
resume object address:0x604000247da0
name:HanMeiMei | 0x10bc0c1b0
gender:female | 0x10bc0c1d0
age:24 | 0xa000000000034322
university name:X| 0xa000000000000581
university start year:2014 | 0xa000000343130324
university end year:2018 | 0xa000000383130324
university major:TeleCommunication | 0x10bc0c1f0

複製代碼
  • 上面兩個是原resume和剛被複制後的 copy resume的信息,能夠看出來不管是這兩個對象的地址仍是它們的值對應的地址都是不一樣的,說明成功地實現了深複製。
  • 下面兩個是原resume和被修改後的 copy_resume的信息,能夠看出來新的copy_resume的值發生了變化,並且值所對應的地址仍是和原resume的不一樣。

注:還能夠用序列化和反序列化的辦法來實現深複製,由於與代碼設計上不是很複雜,不少語言直接提供了接口,故這裏不作介紹。

下面咱們看一下該例子對應的 UML類圖,能夠更直觀地看一下各個成員之間的關係:

代碼對應的類圖

原型模式代碼示例類圖

在這裏須要注意的是:

  • copy方法是NSObject類提供的複製本對象的接口。NSObject相似於Java中的Object類,在Objective-C中幾乎全部的對象都繼承與它。並且這個copy方法也相似於Object類的clone()方法。
  • copyWithZone(NSZone zone)方法是接口NSCopying提供的接口。而由於這個接口存在於實現文件而不是頭文件,因此它不是對外公開的;便是說外部沒法直接調用copyWithZone(NSZone zone)方法。copyWithZone(NSZone zone)方法是在上面所說的copy方法調用後再調用的,做用是將對象的全部數據都進行復制。所以使用者須要在copyWithZone(NSZone zone)方法裏作工做,而不是copy方法,這一點和Java的clone方法不一樣。

優勢

  • 能夠利用原型模式簡化對象的建立過程,尤爲是對一些建立過程繁瑣,包含對象層級比較多的對象來講,使用原型模式能夠節約系統資源,提升對象生成的效率。
  • 能夠很方便得經過改變值來生成新的對象:有些對象之間的差異可能只在於某些值的不一樣;用原型模式能夠快速複製出新的對象並手動修改值便可。

缺點

  • 對象包含的全部對象都須要配備一個克隆的方法,這就使得在對象層級比較多的狀況下,代碼量會很大,也更加複雜。

iOS SDK 和 JDK 中的應用

  • Objective-C中可使用<NSCopying> 協議,配合- (id)copyWithZone:(NSZone *)zone方法; 或者<NSMutableCopying>協議,配合 copyWithZone:/mutableCopyWithZone:方法
  • Java中可讓一個類實現Cloneable接口並實現clone()方法來複制該類的實例。

到這裏設計模式中的建立型模式就介紹完了,讀者能夠結合UML類圖和demo的代碼來理解每一個設計模式的特色和相互之間的區別,但願讀者能夠有所收穫。

另外,本篇博客的代碼和類圖都保存在個人GitHub庫中:knightsj:object-oriented-design中的Chapter2。

下一篇是面向對象系列的第三篇,講解的是面向對象設計模式中的結構型模式。 該系列的第一篇講解的是設計原則,有興趣的讀者能夠移步:面向對象設計的六大設計原則(附 Demo 及 UML 類圖)

參考書籍和教程

本篇已同步到我的博客:面向對象設計的設計模式(一):建立型模式(附 Demo 及 UML 類圖)


筆者在近期開通了我的公衆號,主要分享編程,讀書筆記,思考類的文章。

  • 編程類文章:包括筆者之前發佈的精選技術文章,以及後續發佈的技術文章(以原創爲主),而且逐漸脫離 iOS 的內容,將側重點會轉移到提升編程能力的方向上。
  • 讀書筆記類文章:分享編程類思考類心理類職場類書籍的讀書筆記。
  • 思考類文章:分享筆者平時在技術上生活上的思考。

由於公衆號天天發佈的消息數有限制,因此到目前爲止尚未將全部過去的精選文章都發布在公衆號上,後續會逐步發佈的。

並且由於各大博客平臺的各類限制,後面還會在公衆號上發佈一些短小精幹,以小見大的乾貨文章哦~

掃下方的公衆號二維碼並點擊關注,期待與您的共同成長~

相關文章
相關標籤/搜索