iOS中都有什麼設計模式?各個設計模式的做用 (轉載)

原文地址: http://www.cnblogs.com/dxb123456/p/5479198.htmlphp

一  iOS中都有什麼設計模式?html

1.代理模式ios

2.觀察者模式算法

3.MVC模式編程

4.單例模式swift

5.策略模式
設計模式

6.工廠模式
安全

 

二  各個設計模式的做用?數據結構

(一)代理模式app

在觀察者模式中,一個對象任何狀態的變動都會通知另外的對改變感興趣的對象。這些對象之間不須要知道彼此的存在,這實際上是一種鬆耦合的設計。當某個屬性變化的時候,咱們一般使用這個模式去通知其它對象。

此模式的通用實現中,觀察者註冊本身感興趣的其它對象的狀態變動事件。當狀態發生變化的時候,全部的觀察者都會獲得通知。蘋果的推送通知(Push Notification)就是一個此模式的例子。

若是你要聽從MVC模式的概念,你須要讓模型對象和視圖對象在不相互直接引用的狀況下通訊。這正是觀察者模式的用武之地。

 

Cocoa經過通知(Notifications)和Key-Value Observing(KVO)來實現觀察者模式。

 

在cocoa框架中的Delegate模式中,委託人每每是框架中的對象(視圖中的控件、表視圖神馬的),代理人每每是視圖控制器對象。

在咱們這個例子中UITableView是委託人,代理人首先得知足一個條件:就是在.h文件中申明它擁有代理資格:

@interface WhateverViewController < UITableViewDelegate >
@end

紅色的表示這個視圖控制器擁有UITableView的代理資格。

其次,在.m文件中定義委託人可讓代理人去代替作的事情:

 
//視圖控制器來代辦應該有多少個節
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [NSArray count];
}
//視圖控制器來代辦某個節應該有多少行 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[NSArray objectAtIndex:section]count]; } // 視圖控制器來代辦負責每一個欄格的外觀 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.textField.text = [NSArray objectAtIndex:indexPath.row]; return cell; } //負責當欄格被點擊後須要觸發的事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil]; [self.navigationController pushViewController:anotherViewController]; [anotherViewController release]; } // 這個是可選的,視圖控制器勤快我就幫你代辦,不勤快我就能夠不幫你辦這事兒,(提供哪些個行能夠被編輯) - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return YES; }
// 對特定編輯風格進行操做 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { } }
// 可選,對那些被移動欄格做特定操做 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { }
// 對那些能夠移動的行返回YES - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // 若是不想讓欄格移動,就返回NO return YES; }
 

 好了,當這個委託人須要辦這些事時,代理人本身就站出來幫忙辦了。這就是ios中的Delegate模式。

2、自定義的delegate模式

@interface A:UIView
id transparendValueDelegate;
@property(nomatic, retain) id transparendValueDelegate;

@end

@implementation A
@synthesize transparendValueDelegate

-(void)Call
{ 
NSString* value = @"你好";
[transparendValueDelegate transparendValue: value];
}

@end


@interface B:UIView
NSString* value;
@end

@implementation B -(void)transparendValue:(NSString*)fromValue { value = fromValue; NSLog(@"%@ ,我是B",value); } @end

使用時:

A* a = [[A alloc] init];
B* b = [[B alloc] init];
a. transparendValueDelegate = b;//設置A代理委託對象爲B
[a Call];

這樣就會輸出:

你好,我是B

 委託模式關鍵就在於一個「被」字。這個B是很被動的,隨時就會被你A Call一下。

 

3、爲何會有delegate模式

換句話說,它能夠用來解決神馬問題?

當一個類的某些功能須要被別人來實現,可是既不明確是些什麼功能,又不明確誰來實現這些功能的時候,委託模式就能夠派上用場。

例如你能夠再寫個C類,實現-(void)transparendValue:(NSString*)fromValue {NSLog(@"%@ ,我是C",value); }也是徹底能夠的。換誰來,只要它實現了這個方法,我就能夠委託它來作這個事。

說到底一切都是爲了使類之間的耦合性更鬆散。好的代碼應該對擴展開放,對修改關閉

 

總結來自http://blog.sina.com.cn/s/blog_b638dc89010192qu.html


(二)觀察者模式

在軟件開發中,不管是那種高級語言中總會伴隨着一些最爲經常使用的設計模式,即使就如iOS開發中與咱們打交道最多的無非就是單例模式、觀察者模式和工廠模式了,固然了其餘的設置模式也一樣存在在編程的不少地方。下面就就讓咱們簡單的瞭解下觀察者模式吧!

觀察者模式本質上時一種發佈-訂閱模型,用以消除具備不一樣行爲的對象之間的耦合,經過這一模式,不一樣對象能夠協同工做,同時它們也能夠被複用於其餘地方Observer從Subject訂閱通知,ConcreteObserver實現重現ObServer並將其重載其update方法。一旦SubJect的實例須要通知Observer任何新的變動,Subject會發送update消息來通知存儲在其內部類中所註冊的Observer、在ConcreteObserverupdate方法的實際實現中,Subject的內部狀態可被取得並進行後續處理。其類圖以下:

 


觀察者模式.png

由上面咱們能夠發現觀察者模式無非在是定義對象間的一種一對多的依賴關係,而且當一個對象的狀態發生改變的時候,全部依賴於它的對象都會獲得通知且自動更新。即若是Subject容許其餘觀察者(實現了觀察者接口的對象)對這個Subject的改變進行請閱,當Subject發送了變化,那麼Subject會將這個變化發送給全部的觀察者,觀察者就能對Subject的變化作出更新。其時序圖以下

 


觀察者模式2.png

經過上面的觀察咱們能夠發現若是用N個Observer來拓展Subject的行爲,這些Observer具備處理存儲在Subject中的信息的特定實現,這樣也就實現了前面所說的消除不一樣對象間的耦合的功能了。

那麼瞭解了這些咱們可能就會更像瞭解下咱們在何時纔會去使用觀察者模式呢?

  • 當須要將改變通知全部的對象時,而你又不知道這些對象的具體類型
  • 改變發生在同一個對象中,並須要改變其餘對象將相關的狀態進行更新且不知道有多少個對象。

而一樣的在咱們平常的開發中在Cocoa Touch框架中的的兩種常常打交道的技術KVO與通知都實現了觀察者模式,因此下面咱們討論的重點也就是基於這兩個方面的。

通知

在以前的博文中曾經簡單的提到過一些通知的基礎使用方法,因此一些基本的使用方法再次就不贅述。言歸正傳,在Cocoa Touch框架中NSNotificationCenterNSNotification對象實現了一對多的模型。經過NSNotificationCenter可讓對象之間進行通信,即使這些對象之間並不認識。下面咱們來看下NSNotificationCenter發佈消息的方法:
NSNotification * subjectMessage = [ NSNotification notificationWithName:@"subjectMessage" object: self]; NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter]; [notificationCenter postNotification:subjectMessage];

經過上面的代碼咱們建立了一個名爲subjectMessageNSNotification對象,而後經過notificationCenter來發布這個消息。經過向NSNotificationCenter類發送defaulCenter消息,能夠獲得NSNotificationCenter實例的引用。每一個進程中只有一個默認的通知中心,因此默認的NSNotificationCenter是個單例對象。若是有其餘觀察者定於了其對象的相關事件則能夠經過如下的方法來進行操做:

NSNotificationCenter * notificationCenter1 = [ NSNotificationCenter defaultCenter]; [notificationCenter addObserver: self selector: @selector(update:) name:@"subjectMessage" object: nil ];

通過以上步驟咱們已經向通知中心註冊了一個事件而且經過selector制定了一個方法update:下面咱們能夠實現如下這個方法

- (void)update:(NSNotification*)notification{ if ([[notification name] isEqualToString:@"subjectMessage"]) { NSLog(@"%@",@"猴子派來的救兵去哪了?"); } }

固然最後若是咱們須要對監聽進行銷燬

- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }

瞭解過通知以後咱們來看一下KVO

KVO是Cocoa提供的一種稱爲鍵值觀察的機制,對象能夠經過它獲得其餘對象特定屬性的變動通知。而這個機制是基於NSKeyValueObserving非正式些,Cocoa經過這個協議爲全部遵循協議的對象提供了一種自動化的屬性監聽的功能。
雖然通知KVO均可以對觀察者進行實現,可是他們之間仍是略有不一樣的,由上面的例子咱們能夠看出通知是由一箇中心對象爲全部觀察者提供變動通知,主要是廣義上關注程序事件,而KVO則是被觀察的對象直接想觀察者發送通知,主要是綁定於特定對象屬性的值。下面咱們經過一個簡單的例子來了解下他的一些是使用方法

首先咱們有Hero這個模型

@property (nonatomic,copy) NSString * name; @property (nonatomic,copy) NSString * title; @property (nonatomic,assign) NSUInteger age;

在控制其中咱們將其初始化並賦值

self.hero = [[Hero alloc] init]; self.hero.name = @"趙雲"; self.hero.title = @"將軍"; self.hero.age = 87;

如今咱們的這個對象基本有值了,那麼咱們將這個對象的name監聽下他的改變

[self.hero addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

觸發通知並將值改變

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ self.hero.name = @"張飛"; }

在制定的回調函數中,處理收到的更改通知

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if([keyPath isEqualToString:@"name"]) { NSLog(@"賦值後--%@",self.hero.name); NSLog(@"新的值--%@",change[@"new"]); NSLog(@"之前的值--%@",change[@"old"]); } }

回調打印以下:

 


dayin.png

最後註銷觀察者

- (void)dealloc{ [self.hero removeObserver:self forKeyPath:@"name"]; }

到了這裏觀察者模式中經常使用的KVO通知的內容就到這裏,不過要知道這裏談及的只是最基礎的用法,後面咱們可能仍是有更加深刻的探究,或者在後續中可能還會對比iOS中的代理以及Block來探尋下iOS中的消息傳遞機制,再或者像Swift中的didSetwillSet的屬性監聽的方法,這些都是很好玩的內容,不是麼?

 

(三)MVC模式

MVC根據角色劃分類,涉及到三個角色:

Model:模型保存應用程序的數據。

View:視圖是模型的可視化表示以及用戶交互的控件

Controller:控制器是一個協調全部工做的中介者。它訪問模型中的數據並在視圖中展現它們,同時它們還監聽事件和操做數據。

一個MVC模式的好的實現也就意味着每個對象都會被劃分到上面所說的組中。

咱們能夠很好的用下圖來描述經過控制器實現的視圖到模型的交互過程:

技術分享

模型會把任何數據的變動通知控制器,而後控制器更新視圖數據。視圖對象通知控制器用戶的操做,控制器要麼根據須要來更新模型,要麼檢索任何被請求的數據。

你可能在想爲何不能僅僅使用控制器,在一個類中實現視圖和模型,這樣貌似更加容易?

全部的這些都歸結於代碼關注點分離以及複用。在理想的狀態下,視圖應該和模型徹底的分離。若是視圖不依賴某個實際的模型,那麼視圖就能夠被複用來展現不一樣模型的數據。

舉個例子來講,若是未來你打算加入電影或者書籍到你的資料庫中,你仍然可使用一樣的AlbumView去顯示電影和書籍數據。更進一步來講,若是你想建立一個新的與專輯有關聯的工程,你能夠很簡單的複用Album類,由於它不依賴任何視圖。這就是MVC的強大之處。

 


(四)單例模式

單例設計模式確保對於一個給定的類只有一個實例存在,這個實例有一個全局惟一的訪問點。它一般採用懶加載的方式在第一次用到實例的時候再去建立它。

 

注意:蘋果大量使用了此模式。例如:[NSUserDefaults standardUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager],全部的這些方法都返回一個單例對象。

 

你極可能會想爲何這麼關心是否一個類有多個實例?畢竟代碼和內存都是廉價的,對嗎? 

有一些狀況下,只有一個實例顯得很是合理。舉例來講,你不須要有多個Logger的實例,除非你想去寫多個日誌文件。或者一個全局的配置處理類:實現線程安全的方式訪問共享實例是容易的,好比一個配置文件,有好多個類同時修改這個文件。

 


(五)策略模式

1.概述

在軟件開發中也經常遇到相似的狀況,實現某一個功能有多種算法或者 策略,咱們能夠根據環境或者條件的不一樣選擇不一樣的算法或者策略來完成該功能 。如查找、排序等,一種經常使用的方法是硬編碼(Hard Coding)在一個類中,如須要提供多種查找算法,能夠將這些算法寫到一個類中,在該類中提供多個方法,每個方法對應一個具體的查找算法;固然也能夠將這些查找算法封裝在一個統一的方法中,經過if…else…或者 case 等條件判斷語句來進行選擇。這兩種實現方法咱們均可以稱之爲硬編碼,若是須要增長一種新的查找算法,須要修改封裝算法類的源代碼;更換查找算法,也須要修改客戶端調用代碼。在這個算法類中封裝了大量查找算法, 該類代碼將較複雜,維護較爲困難。若是咱們將這些策略包含在客戶端 ,這種作法更不可取,將致使客戶端程序龐大並且難以維護,若是存在大量可供選擇的算法時問題將變得更加嚴重。

例子1:一個菜單功能可以根據用戶的「皮膚」首選項來決定是否採用水平的仍是垂直的排列形式。同事能夠靈活增長菜單那的顯示樣式。

例子2:出行旅遊:咱們 能夠有幾個策略能夠考慮:能夠騎自行車,汽車,作火車,飛機。每一個策略均可以獲得相同的結果,可是它們使用了不一樣的資源。選擇策略的依據是費用,時間,使用工具還有每種方式的方便程度 。

2.問題

 

如何讓算法和對象分開來,使得算法能夠獨立於使用它的客戶而變化? 

3.解決方案

策略模式: 定 義一系列的算法,把每個算法封裝起來, 而且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。 也稱爲 政策模式 (Policy) 。( Definea family of algorithms,encapsulate each one, andmake them interchangeable. Strategy lets the algorithmvary independently from clients that use it.  )

策略模式把對象自己和運算規則區分開來,其 功能很是強大,由於這個設計模式自己的核心思想就是面向對象編程的多形性的思想。

4.適用性

 

當存在如下狀況時使用Strategy模式

1)• 許多相關的類僅僅是行爲有異。 「策略」提供了一種用多個行爲中的一個行爲來配置一個類的方法。即一個系統須要動態地在幾種算法中選擇一種。

2)• 須要使用一個算法的不一樣變體。例如,你可能會定義一些反映不一樣的空間 /時間權衡的算法。當這些變體實現爲一個算法的類層次時 ,可使用策略模式。

3)• 算法使用客戶不該該知道的數據。可以使用策略模式以免暴露覆雜的、與算法相關的數據結構。

4)• 一個類定義了多種行爲 , 而且這些行爲在這個類的操做中以多個條件語句的形式出現。將相關的條件分支移入它們各自的Strategy類中以代替這些條件語句。

 

5.結構

6.效果

Strategy模式有下面的一些優勢:

 

1) 相關算法系列 

Strategy類層次爲Context定義了一系列的可供重用的算法或行爲。 繼承有助於析取出這些算法中的公共功能。 

 

2) 提供了能夠替換繼承關係的辦法

: 繼承提供了另外一種支持多種算法或行爲的方法。你能夠直接生成一個Context類的子類,從而給它以不一樣的行爲。但這會將行爲硬行編制到 Context中,而將算法的實現與Context的實現混合起來,從而使Context難以理解、難以維護和難以擴展,並且還不能動態地改變算法。最後你獲得一堆相關的類 , 它們之間的惟一差異是它們所使用的算法或行爲。 將算法封裝在獨立的Strategy類中使得你能夠獨立於其Context改變它,使它易於切換、易於理解、易於擴展。 

 

3) 消除了一些if else條件語句

:Strategy模式提供了用條件語句選擇所需的行爲之外的另外一種選擇。當不一樣的行爲堆砌在一個類中時 ,很難避免使用條件語句來選擇合適的行爲。將行爲封裝在一個個獨立的Strategy類中消除了這些條件語句。含有許多條件語句的代碼一般意味着須要使用Strategy模式。 

4) 實現的選擇

Strategy模式能夠提供相同行爲的不一樣實現。客戶能夠根據不一樣時間 /空間權衡取捨要求從不一樣策略中進行選擇。

Strategy模式缺點 : 

 

1)客戶端必須知道全部的策略類,並自行決定使用哪個策略類

:  本模式有一個潛在的缺點,就是一個客戶要選擇一個合適的Strategy就必須知道這些Strategy到底有何不一樣。此時可能不得不向客戶暴露具體的實現問題。所以僅當這些不一樣行爲變體與客戶相關的行爲時 , 才須要使用Strategy模式。 

 

2 ) Strategy和Context之間的通訊開銷

:不管各個ConcreteStrategy實現的算法是簡單仍是複雜, 它們都共享Strategy定義的接口。所以極可能某些 ConcreteStrategy不會都用到全部經過這個接口傳遞給它們的信息;簡單的 ConcreteStrategy可能不使用其中的任何信息!這就意味着有時Context會建立和初始化一些永遠不會用到的參數。若是存在這樣問題 , 那麼將須要在Strategy和Context之間更進行緊密的耦合。 

3 )策略模式將形成產生不少策略類

:能夠經過使用享元模式在必定程度上減小對象的數量。 增長了對象的數目 Strategy增長了一個應用中的對象的數目。有時你能夠將 Strategy實現爲可供各Context共享的無狀態的對象來減小這一開銷。任何其他的狀態都由 Context維護。Context在每一次對Strategy對象的請求中都將這個狀態傳遞過去。共享的 Strategy不該在各次調用之間維護狀態。

7. iOS應用分析

例如,咱們在驗證用戶輸入的表單的時候,加入包括電話輸入框的驗證和郵件輸入框的驗證,這兩部分的驗證算法是不一樣的,若是把這個算法當作一個函數,他幾乎有相同的輸入參數和返回參數。咱們能夠把這個相同的函數能夠抽象爲基類(InputValidator)的一個方法(bool validateInput(input,error)),而後抽象出兩個具體的策略類:電話驗證類(PhoneValidator)和郵件驗證類(EmailValidator),他們須要在各自的實現裏面去複寫父類的驗證方法。爲了可以正常的調用到驗證類的驗證方法,咱們須要自定義一個UITextField的子類CustomTextField,其中有一個InputValidator類型的引用和一個validate方法,該方法裏面調用InputValidator的驗證方法,而後在textFieldDidEndEditing代理方法裏面調用CustomTextField的validate方法,這樣就不用咱們在判斷輸入是否合法的時候經過if else去處理每種邏輯,並且這樣作方便擴展,提升可複用性。 

實例:排序算法,NSArray的sortedArrayUsingSelector;經典的鴨子會叫,會飛案例。  


(六)工廠模式

工廠模式個人理解是:他就是爲了建立對象的

建立對象的時候,咱們通常是alloc一個對象,若是須要建立100個這樣的對象,若是是在一個for循環中還好說,直接一句alloc就好了,可是事實並不那麼如意,咱們可能會在不一樣的地方去建立這個對象,那麼咱們可能須要寫100句alloc 了,可是若是咱們在建立對象的時候,須要在這些對象建立完以後,爲它的一個屬性添加一個固定的值,比方說都是某某學校的學生,那麼可能有須要多些100行重複的代碼了,那麼,若是寫一個-(void)createObj方法,把建立對象和學校屬性寫在這個方法裏邊,那麼就是會省事不少,也就是說咱們能夠alloc 建立對象封裝到一個方法裏邊,直接調用這個方法就能夠了,這就是簡單工廠方法

代碼結構以下

Animal 類

@interface Animal :NSObject

@proterty(nonatomic,strong) NSString *name;

-(void)laugh;

@end

Dog類

 

@interface Dog:Animal

@end

 

Cat類

@interface Cat:Animal

@end

 

建立對象的工廠類

.h

@interface AnimalFactory:NSObject

+(Dog *)createDog;

+(Cat *)createCat;

@end

.m

@implementation AnimalFactory

+(Dog *)createDog{

    Dog *dog=[[Dog alloc]init];

    dog.name=@「baby」;

    return dog;

}

 

+(Cat *) createCat{

    Cat *cat=[[Cat alloc]init];

    return cat;

}

Main.m文件

Dog *dog=[AnimalFactory createDog];

Cat *cat=[AnimalFactory createCat];

這是簡單工廠模式

如今建立100個Dog對象,若是這100個對象寫在程序中的不一樣地方,按上邊的方法是須要把Dog *dog=[AnimalFactory createDog];這一句話寫在程序中不少不一樣的地方,那麼如今有一個需求,就是若是須要把這些建立的100個Dog對象所有變成Cat對象,那麼按照剛纔的那個作法,就須要在這100句代碼中把createDog方法變成createCat方法了,這樣作仍是很複雜

那麼這個時候用工廠方法模式就能解決這個難題了

工廠方法模式是爲每個要建立的對象所在的類都相應地建立一個工廠

代碼以下

@interface AnimalFactory:NSObject

-(Animal*)createAnimal;

@end;

Dog工廠類

@interface DogFactory:AnimalFactory;

@implementation DogFactory

-(Animal *)createAnimal{

retrurn [[Dog alloc]init];

}

@end

Cat工廠類

@interface CatFactory:AnimalFactory;

@implementation Cat Factory

-(Animal *)createAnimal

retrurn [[Cat alloc]init];

}

@end

Main.m

AnimalFactory *dogFactory=[[DogFactory alloc]init];

 

Animal *animal1=[dogFactory createAnimal];

[animal1 laugh];

Animal *animal2=[dogFactory createAnimal];

[animal2 laugh];

…….

Animal *animal100=[dogFactory createAnimal];

[animal100 laugh];

這樣話若是要把100個Dog改成Cat的話,只須要吧DogFactory改成CatFactory就能夠了

 

可是工廠方法也有它的限制:

1.要建立的類必須擁有同一個父類

2.要建立的類在100個不一樣的地方所調用的方法必須同樣

以上這些只是我的感悟,會有一些不足的地方,請你們幫忙改正,嘿嘿

相關文章
相關標籤/搜索