在iOS中Delegate使用單例模式保證只有一份物件,那麼多個單例的情況,可以使用享元模式,降低了物件的讀寫次數,提高了效能,使用NSString、NSArray、NSMutableArray
等使用了建立型的抽象工廠模式,保留了內部建立步驟,產出多個型別產品,AppDelegate
使用狀態模式來改變APP的狀態,UIView
使用外觀模式封裝了一系列介面使view顯示出來,tableview
使用代理模式實現了view
和資料的分離。其實還有很多我們在用而不是很清楚的設計模式,那麼我們就來看下常用的設計模式。
設計模式
設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、程式碼設計經驗的總結。 使用設計模式的目的:為了程式碼可重用性、讓程式碼更容易被他人理解、保證程式碼可靠性。 設計模式使程式碼編寫真正工程化;設計模式是軟體工程的基石脈絡,如同大廈的結構一樣。
設計模式分為建立型、結構型模式、行為型模式,通過借來一張圖來表示一下
建立型模式
這些設計模式提供了一種在建立物件的同時隱藏建立邏輯的方式,而不是使用 new 運算子直接例項化物件。這使得程式在判斷針對某個給定例項需要建立哪些物件時更加靈活。
1.簡單工廠模式
簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式,它屬於類建立型模式。在簡單工廠模式中,可以根據引數的不同返回不同類的例項。簡單工廠模式專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。
在工廠模式中,我們在建立物件時不會對客戶端暴露建立邏輯,並且是通過使用一個共同的介面來指向新建立的物件。
Sample sample=new Sample(引數);
複製程式碼
在OC中我們通常這樣子用
// productMethod 產品的方法
@protocol Product <NSObject>
-(void)productMethod;
@end
//工廠類
@interface SimpleFactory : NSObject
+(id<Product>)createProduct:(NSString *)productName;
@end
//產品A 實現協議代替 抽象方法
@interface ProductA : NSObject<Product>
@end
//產品B 實現協議代替 抽象方法
@interface ProductB : NSObject<Product>
@end
@class ProductA,ProductB;
@implementation SimpleFactory
+ (id<Product>)createProduct:(NSString *)productName{
if ([productName isEqualToString:NSStringFromClass(ProductA.class)]) {
return [[ProductA alloc]init];
}else if ([productName isEqualToString:NSStringFromClass(ProductB.class)]){
return [[ProductB alloc]init];
}else{
return nil;
}
}
@end
@implementation ProductA
- (void)productMethod {
}
@end
@implementation ProductB
- (void)productMethod {
}
@end
複製程式碼
使用的時候是這樣子
//建立產品A
ProductA *a =[SimpleFactory createProduct:NSStringFromClass(ProductA.class)];
[a productMethod];
//建立產品B
ProductB *b =[SimpleFactory createProduct:NSStringFromClass(ProductB.class)];
[b productMethod];
複製程式碼
優點是通過一個引數確定想要的哪個類的例項,而不用關心內部如何實現,缺點是新增加一個產品需要更改createProduct:(NSString *)productName
的實現。
2.工廠模式
工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多型工廠(Polymorphic Factory)模式,它屬於類建立型模式。在工廠方法模式中,工廠父類負責定義建立產品物件的公共介面,而工廠子類則負責生成具體的產品物件,這樣做的目的是將產品類的例項化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該例項化哪一個具體產品類。
工廠方法模式包含如下角色:
- Product:抽象產品
- ProductA:具體產品
- Factory:抽象工廠
- FactoryA:具體工廠
//工廠抽象方法
@protocol Factory <NSObject>
+ (void)createProduct:(NSString *)productName;
@end
//工廠類A
@interface FactoryA : NSObject<Factory>
+(id<Product>)createProduct:(NSString *)productName;
@end
//工廠類B
@interface FactoryB : NSObject<Factory>
+(id<Product>)createProduct:(NSString *)productName;
@end
//建立產品A
@implementation FactoryA
+ (id<Product>)createProduct:(NSString *)productName{
if ([productName isEqualToString:NSStringFromClass(ProductA.class)]) {
return [[ProductA alloc]init];
}else{
return nil;
}
}
@end
//建立產品B
@implementation FactoryB
+ (id<Product>)createProduct:(NSString *)productName{
if ([productName isEqualToString:NSStringFromClass(ProductB.class)]){
return [[ProductB alloc]init];
}else{
return nil;
}
}
@end
複製程式碼
使用起來很簡單
//建立產品A
ProductA *a =[FactoryA createProduct:NSStringFromClass(ProductA.class)];
[a productMethod];
//建立產品B
ProductB *b =[FactoryB createProduct:NSStringFromClass(ProductB.class)];
[b productMethod];
複製程式碼
優點是當建立新的產品的時候,不需要對舊生產線進行更改,只需要新增一個方法即可,缺點是產品是單一的生產線,則工廠繼承協議,稍顯複雜,功能退化成簡單工廠模式。
3.抽象工廠模式
抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬於物件建立型模式。
抽象工廠模式包含如下角色:
- Factory:抽象工廠
- FactoryA/B:具體工廠
- ProductA/B:抽象產品
- ProductA1/A2:具體產品
- ProductB1/B2:具體產品
// productMethod 產品的方法
@protocol ProductA <NSObject>
-(void)productMethod;
@end
@protocol ProductB <NSObject>
-(void)productMethod;
@end
//工廠抽象方法
@protocol Factory <NSObject>
//建立產品A例項
+ (id<ProductA>)createProductA:(NSString *)ProductAName;
//建立產品B例項
+ (id<ProductB>)createProductB:(NSString *)ProductBName;
@end
//工廠類A 協議在.m中實現
@interface Factory1 : NSObject<Factory>
@end
//工廠類B 協議在.m中實現
@interface Factory2 : NSObject<Factory>
@end
//產品A 實現協議代替 抽象方法 協議在.m中實現
@interface ProductA1 : NSObject<ProductA>
@end
@interface ProductA2 : NSObject<ProductA>
@end
//產品B 實現協議代替 抽象方法 協議在.m中實現
@interface ProductB1 : NSObject<ProductB>
@end
@interface ProductB2 : NSObject<ProductB>
@end
複製程式碼
使用起來很簡單,首先建立工廠,然後根據工廠來產出想要的產品。
//A工廠生產產品
ProductA1 *a1 =[Factory1 createProductA:NSStringFromClass(ProductA1.class)];
ProductA1 *a2 =[Factory1 createProductA:NSStringFromClass(ProductA2.class)];
[a1 productMethod];
[a2 productMethod];
//B工廠生產產品B
//此處 省略程式碼
複製程式碼
優點很明顯只需要更改工廠就可以改變生產流水線,缺點是當需要進行新增一個產品,則需要對工廠的所有子類進行更改。
三個工廠模式聯絡
當抽象工廠模式中每一個具體工廠類只建立一個產品物件,也就是隻存在一個產品等級結構時,抽象工廠模式退化成工廠方法模式;當工廠方法模式中抽象工廠與具體工廠合併,提供一個統一的工廠來建立產品物件,並將建立物件的工廠方法設計為靜態方法時,工廠方法模式退化成簡單工廠模式。
簡單工廠有一個靜態方法生產一個產品,工廠模式是工廠方法抽象出來生產一個產品,抽象工廠是工廠抽象方法生產多個產品。
4.建造者模式
建造者模式(Builder Pattern):將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
建造者模式是一步一步建立一個複雜的物件,它允許使用者只通過指定複雜物件的型別和內容就可以構建它們,使用者不需要知道內部的具體構建細節。建造者模式屬於物件建立型模式。根據中文翻譯的不同,建造者模式又可以稱為生成器模式。
建造者模式包含如下角色:
- Builder:抽象建造者
- ConcreteBuilder:具體建造者
- Director:指揮者
- Product:產品角色
程式碼
@protocol Builder <NSObject>
@optional
- (void)buildPartA;
- (void)buildPartB;
- (void)buildPartC;
- (instancetype)getResult;
@end
@interface BuilderA : NSObject<Builder>
- (void)buildPartA;
@end
@interface BuilderB : NSObject<Builder>
- (void)buildPartB;
@end
@interface Builder : NSObject
- (id)constuct;//加工
- (void)setBuilder:(id<Builder>)bd;
@end
//實現
//.m
@implementation BuilderA
- (void)buildPartA{
printf("build A");
}
-(instancetype)getResult
{
return self;
}
@end
@implementation BuilderB
- (void)buildPartB{
printf("build B");
}
-(instancetype)getResult
{
return self;
}
@end
@interface Builder ()
{
id<Builder> _bd;
}
@end
@implementation Builder
- (id)constuct{
//加工幾個步驟
[_bd buildPartA];
[_bd buildPartB];
[_bd buildPartC];
//組裝得到產品
return [_bd getResult];
}
- (void)setBuilder:(id<Builder>)bd{
_bd = bd;
}
@end
複製程式碼
優點是客戶不知道具體的生產步驟,將生產步驟和過程解耦,可以相同的步驟(有子類實現不同過程)生產不同的產品,擴充套件方便,只需要(子類)實現每個步驟,缺點是多個產品相似點很多才能抽象出來步驟。
5. 單例模式
單例模式(Singleton Pattern):單例模式確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項,這個類稱為單例類,它提供全域性訪問的方法。
單例模式的要點有三個:一是某個類只能有一個例項;二是它必須自行建立這個例項;三是它必須自行向整個系統提供這個例項。單例模式是一種物件建立型模式。單例模式又名單件模式或單態模式。
單例模式包含如下角色:
- Singleton:單例
程式碼
@interface Singleton : NSObject
+ (instancetype)getInstace;
@end
@implementation Singleton
+ (instancetype)getInstace{
static dispatch_once_t onceToken;
static Singleton *_t;
dispatch_once(&onceToken, ^{
_t = [Singleton new];
});
return _t;
}
@end
複製程式碼
使用起來也很簡單
Singleton *ton=[Singleton getInstace];
//next code
複製程式碼
優點記憶體中該類的例項化只有一次,省略了頻繁建立和銷燬步驟,提高了效能。缺點是單例模式沒有抽象層,擴充套件比較困難。
結構型模式
結構型模式(Structural Pattern)描述如何將類或者對 象結合在一起形成更大的結構,就像搭積木,可以通過 簡單積木的組合形成複雜的、功能更為強大的結構。
結構型模式包含模式
- 介面卡模式(Adapter)
- 橋接模式(Bridge)
- 裝飾模式(Decorator)
- 外觀模式(Facade)
- 享元模式(Flyweight)
- 代理模式(Proxy)
6.介面卡模式
介面卡模式(Adapter Pattern) :將一個介面轉換成客戶希望的另一個介面,介面卡模式使介面不相容的那些類可以一起工作,其別名為包裝器(Wrapper)。介面卡模式既可以作為類結構型模式,也可以作為物件結構型模式。
介面卡模式包含如下角色:
- Target:目標抽象類
- Adapter:介面卡類
- Adaptee:適配者類
- Client:客戶類
程式碼
@interface Adaptee : NSObject
- (void)specificRequest;
@end
@interface Adapter : NSObject
@property (nonatomic,strong) Adaptee *adaptee;
+ (instancetype)initWithAdaptee:(Adaptee *)obj;
- (void)request;
@end
@implementation Adaptee
- (void)specificRequest{
NSLog(@"介面卡 第三方工人幹活了");
}
@end
@implementation Adapter
+ (instancetype)initWithAdaptee:(Adaptee *)obj{
Adapter *adapter=[Adapter new];
adapter.adaptee = obj;
return adapter;
}
//通過介面卡 指導三方工人幹活,達到 客戶忽略過程,多個客戶可以複用介面卡程式碼
- (void)request{
[self.adaptee specificRequest];
}
@end
複製程式碼
優點是經過加工第三方可以為客戶服務了,缺點是不支援多繼承的一次只能適配一個。
7.橋接模式
橋接模式(Bridge Pattern):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種物件結構型模式,又稱為柄體(Handle and Body)模式或介面(Interface)模式。
橋接模式包含如下角色:
- Abstraction:抽象類
- RefinedAbstraction:擴充抽象類
- Implementor:實現類介面
- ConcreteImplementor:具體實現類
優點是抽象Implementor
,具體實現在Implementor
子類實現,降低耦合。缺點是橋接模式的引入會增加系統的理解與設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計與程式設計。
8.裝飾模式
裝飾模式(Decorator Pattern) :動態地給一個物件增加一些額外的職責(Responsibility),就增加物件功能來說,裝飾模式比生成子類實現更為靈活。其別名也可以稱為包裝器(Wrapper),與介面卡模式的別名相同,但它們適用於不同的場合。根據翻譯的不同,裝飾模式也有人稱之為“油漆工模式”,它是一種物件結構型模式。 裝飾模式包含如下角色:
- Component: 抽象構件
- ConcreteComponent: 具體構件
- Decorator: 抽象裝飾類
- ConcreteDecorator: 具體裝飾類
程式碼
//定義了協議
@protocol ComponentProtocol <NSObject>
- (void)opertion;
@end
//實現協議的類
@interface ComponentA : NSObject<ComponentProtocol>
@end
@interface ComponentB : NSObject<ComponentProtocol>
@end
//ComponentA的分類
@interface Component : ComponentA(add)
- (void)addMethod;
@end
//實現部分
//.m
@implementation ComponentA
- (void)opertion{
NSLog(@"ComponentA opertion ");
}
@end
@implementation ComponentB
- (void)opertion{
NSLog(@"ComponentB opertion ");
}
@end
//ComponentA的分類
@implementation Component(add)
- (void)addMethod{
NSLog(@"addMethod");
}
@end
複製程式碼
優點動態新增功能(iOS中的分類),缺點是類變多(多個分類)時,排查錯誤不好排查。
9.外觀模式
外觀模式(Facade Pattern):外部與一個子系統的通訊必須通過一個統一的外觀物件進行,為子系統中的一組介面提供一個一致的介面,外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。外觀模式又稱為門面模式,它是一種物件結構型模式。
外觀模式包含如下角色:
- Facade: 外觀角色
- SubSystem:子系統角色
//子系統角色
@interface SystemA : NSObject
- (void)run;
@end
//子系統角色
@interface SystemB : NSObject
- (void)eat;
@end
//子系統角色
@interface SystemC : NSObject
- (void)play;
@end
//外觀角色
@interface Facade : NSObject
@property (nonatomic,strong) SystemA *a;
@property (nonatomic,strong) SystemB *b;
@property (nonatomic,strong) SystemC *c;
@end
複製程式碼
優點降低使用者和子系統的耦合,而且可以通過外觀訪問子系統,子系統可移植性強,缺點是外觀沒有進行抽象化,更改子系統必須更改外觀類。
10.享元模式
享元模式(Flyweight Pattern):運用共享技術有效地支援大量細粒度物件的複用。系統只使用少量的物件,而這些物件都很相似,狀態變化很小,可以實現物件的多次複用。由於享元模式要求能夠共享的物件必須是細粒度物件,因此它又稱為輕量級模式,它是一種物件結構型模式。
享元模式包含如下角色:
- Flyweight: 抽象享元類
- ConcreteFlyweight: 具體享元類
- UnsharedConcreteFlyweight: 非共享具體享元類
- FlyweightFactory: 享元工廠類
@interface FYFly : NSObject
@property (nonatomic,strong) NSMutableDictionary * dic;
@end
@protocol FlyweightProtocol <NSObject>
- (void)play;
@end
@interface FlyweightA : NSObject<FlyweightProtocol>
- (void)eat;
@end
@interface FlyweightB : NSObject<FlyweightProtocol>
- (void)run;
@end
@implementation FlyweightA
- (void)play{
NSLog(@"我在玩耍");
}
- (void)eat{
NSLog(@"我在吃飯");
}
@end
@implementation FlyweightB
- (void)play{
NSLog(@"我在玩耍");
}
- (void)run{
NSLog(@"我在跑步");
}
@end
複製程式碼
優點多個重複使用率高的物件使用該模式,可以提高效率,缺點使系統更加複雜。
11.代理模式
代理模式比較簡單,系統的tableView
中就是使用代理實現的。
行為型模式
行為型模式(Behavioral Pattern)是對在不同的物件之間劃分責任和演算法的抽象化。 行為型模式不僅僅關注類和物件的結構,而且重點關注它們之間的相互作用。 通過行為型模式,可以更加清晰地劃分類與物件的職責,並研究系統在執行時例項物件 之間的互動。在系統執行時,物件並不是孤立的,它們可以通過相互通訊與協作完成某些複雜功能,一個物件在執行時也將影響到其他物件的執行。
行為型模式分為類行為型模式和物件行為型模式兩種:
-
類行為型模式:類的行為型模式使用繼承關係在幾個類之間分配行為,類行為型模式主要通過多型等方式來分配父類與子類的職責。
-
物件行為型模式:物件的行為型模式則使用物件的聚合關聯關係來分配行為,物件行為型模式主要是通過物件關聯等方式來分配兩個或多個類的職責。根據“合成複用原則”,系統中要儘量使用關聯關係來取代繼承關係,因此大部分行為型設計模式都屬於物件行為型設計模式。
包含模式
- 職責鏈模式(Chain of Responsibility)
- 命令模式(Command)
- 直譯器模式(Interpreter)
- 迭代器模式(Iterator)
- 中介者模式(Mediator)
- 備忘錄模式(Memento)
- 觀察者模式(Observer)
- 狀態模式(State)
- 策略模式(Strategy)
- 模板方法模式(Template Method)
- 訪問者模式(Visitor)
下面我們挑選幾種重要的演練一下
12命令模式
命令模式(Command Pattern):將一個請求封裝為一個物件,從而使我們可用不同的請求對客戶進行引數化;對請求排隊或者記錄請求日誌,以及支援可撤銷的操作。命令模式是一種物件行為型模式,其別名為動作(Action)模式或事務(Transaction)模式。
命令模式包含如下角色:
- Command: 抽象命令類
- ConcreteCommand: 具體命令類
- Invoker: 呼叫者
- Receiver: 接收者
- Client:客戶類
程式碼
@interface Order : NSObject
- (void)exe;
@end
@protocol CommandProtocol <NSObject>
- (void)play;
@end
@interface Order1 : NSObject<CommandProtocol>
@end
@interface Order2 : NSObject<CommandProtocol>
@end
@interface Order3 : NSObject<CommandProtocol>
@end
@implementation Order
- (void)exe{
[[Order1 new] play];
}
@end
@implementation Order1
- (void)play {
NSLog(@"進入公園");
[[Order2 new] play];
}
@end
@implementation Order2
- (void)play {
NSLog(@"開始打球");
[[Order3 new] play];
}
@end
@implementation Order3
- (void)play{
NSLog(@"開始打羽毛球");
}
@end
複製程式碼
優點類之間耦合度低,缺點單一的命令會造成過多的實體類。
13中介者模式
中介者模式(Mediator Pattern)定義:用一箇中介物件來封裝一系列的物件互動,中介者使各物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。中介者模式又稱為調停者模式,它是一種物件行為型模式。
中介者模式包含如下角色:
- Mediator: 抽象中介者
- ConcreteMediator: 具體中介者
- Colleague: 抽象同事類
- ConcreteColleague: 具體同事類
@interface Meditor : NSObject
- (void)registerObj:(NSString *)key;
- (void)sendMsg:(NSString *)key msg:(NSString *)msg;
@end
@protocol ColleagueProtocol <NSObject>
- (void)sendmsg:(NSString *)msg;
@end
@interface ColleagueA : NSObject<ColleagueProtocol>
@end
@interface ColleagueB : NSObject<ColleagueProtocol>
@end
@interface Meditor(){
NSMutableDictionary *_dic;
}
@end
@implementation Meditor
- (void)registerObj:(NSString *)key id:(id<ColleagueProtocol>)obj{
if (_dic ==nil) {
_dic=[NSMutableDictionary dictionary];
}
[_dic setObject:key forKey:obj];
}
- (void)sendMsg:(NSString *)key msg:(NSString *)msg{
id <ColleagueProtocol> obj = _dic[key];
[obj sendmsg:msg];
}
@end
@implementation ColleagueA
- (void)sendmsg:(NSString *)msg{
NSLog(@"ColleagueA send %@",msg);
}
@end
@implementation ColleagueB
- (void)sendmsg:(NSString *)msg{
NSLog(@"ColleagueB send %@",msg);
}
@end
複製程式碼
優點簡化對相互之間互動,降低耦合,缺點會導致終結者非常複雜。
14觀察者模式
觀察者模式(Observer Pattern):定義物件間的一種一對多依賴關係,使得每當一個物件狀態發生改變時,其相關依賴物件皆得到通知並被自動更新。觀察者模式又叫做釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式是一種物件行為型模式。
觀察者模式包含如下角色:
- Subject: 目標
- ConcreteSubject: 具體目標
- Observer: 觀察者
- ConcreteObserver: 具體觀察者
@interface ViewController ()
@property (nonnull,nonatomic,assign) int age;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self addObserver:self forKeyPath:@"age"
options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"%@",change);
}
@end
複製程式碼
優點可以實時監測到物件的變化,缺點是訂閱者過多會造成效能低下,觀察者只知道變化的結果,不瞭解變化的是如何變化的。
15狀態模式
狀態模式(State Pattern) :允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類。其別名為狀態物件(Objects for States),狀態模式是一種物件行為型模式。
狀態模式包含如下角色:
- Context: 環境類
- State: 抽象狀態類
- ConcreteState: 具體狀態類
typedef enum : NSUInteger {
StateClose = 0,
StateOpen = 1,
} State;
@interface StateClass : NSObject
@property (nonatomic,assign) State s;
@end
@implementation StateClass
- (void)setS:(State)s{
switch (s) {
case StateOpen:
{
NSLog(@"飛機已啟動");
}
break;
case StateClose:
{
NSLog(@"飛機已落地");
}
break;
default:
break;
}
}
@end
複製程式碼
優點是使用狀態控制類的行為,缺點是新增狀態需要修改狀態類對應的原始碼。
16策略模式
策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)。
策略模式包含如下角色:
- Context: 環境類
- Strategy: 抽象策略類
- ConcreteStrategy: 具體策略類
@interface Strategy : NSObject
- (void)handle;
@end
@interface StrategyA : NSObject
- (void)handle;
@end
@interface StrategyB : NSObject
- (void)handle;
@end
@interface Context : NSObject
@property (nonatomic,strong) Strategy *obj;
- (void)opertion;
@end
@implementation Context
- (void)opertion{
[self.obj handle];
}
@end
@implementation Strategy
- (void)handle{}
@end
@implementation StrategyA
- (void)handle{
NSLog(@"老三 算數");
}
@end
@implementation StrategyB
- (void)handle{
NSLog(@"老四 算數");
}
@end
複製程式碼
優點可以靈活增加演算法,缺點是客戶必須知道策略的演算法從而決定了解使用哪個演算法,策略會產生多個物件,可以使用享元模式進行物件管理。
參考資料
廣告時間