第一章,你好,設計模式html
圖書相關的一些資源ios
http://www.ocdesignpatterns.com/git
源代碼下載地址 www.apress.comgithub
設計模式是爲特定場景下的問題而定製的解決方案。算法
針對接口編程,而不是針對實現編程編程
接口定義了類型。類繼承與藉口繼承的關係canvas
類繼承是經過複用父類的功能,來定義對象新的實現的一種機制。設計模式
使用接口的好處:網絡
只要對象符合客戶端所要求的接口,客戶端就沒必要在乎所使用對象的確切類型。數據結構
客戶端只知道定義接口的協議或者抽象類,所以客戶端對對象的類一無所知。
原型模式:使用原型實例指定建立對象的種類,並經過複製這個原型建立新的對象。
第4章 工廠模式
對調用的類來講,只須要知道事物的基類和工廠的實現類就能夠,
返回的是抽象類。
抽象工廠 CanvasViewGenerator.h #import "CanvasView.h" @interface CanvasViewGenerator :NSObject - (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame; @end CanvasViewGenerator.m #import "CanvasViewGenerator.h" @implement CanvasViewGenerator - (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{ return [[CanvasView alloc]initWithFrame:aFrame]; } @end 抽象實體 實現工廠 PaperCanvasViewGenerator.h #import "CanvasViewGenerator.h" #import "PaperCanvasView.h" @interface PaperCanvasViewGenerator :CanvasViewGenerator - (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame; @end PaperCanvasViewGenerator.m #import "PaperCanvasViewGenerator.h" @implement PaperCanvasViewGenerator - (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{ return [[CanvasView alloc]initWithFrame:aFrame]; } ClothCanvasViewGenerator.h #import "ClothCanvasViewGenerator.h" #import "ClothCanvasView.h" @interface ClothCanvasViewGenerator :CanvasViewGenerator - (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame; @end ClothCanvasViewGenerator.m #import "ClothCanvasViewGenerator.h" @implement ClothCanvasViewGenerator - (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{ return [[ClothCanvasView alloc]initWithFrame:aFrame]; } 實現實體 #import <UIKit/UIKit.h> #import "CanvasView.h" #import "PaperCanvasView.h" @interface PaperCanvasView:CanvasView //私有變量 //私有方法 - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { UIImage *backgroundImage = [UIImage imageNamed:@"paper"]; UIImageView *backgroundView = [[UIImageView alloc]initWithImage:backgroundImage]; [self addSubview:backgroundView]; } return self; } @end #import <UIKit/UIKit.h> #import "CanvasView.h" #import "ClothCanvasView.h" @interface ClothCanvasView:CanvasView //私有變量 //私有方法 - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { UIImage *backgroundImage = [UIImage imageNamed:@"cloth"]; UIImageView *backgroundView = [[UIImageView alloc]initWithImage:backgroundImage]; [self addSubview:backgroundView]; } return self; } @end //客戶端調用工廠方法,客戶端和具體的實現是解耦的, //若是後續須要增長一種新的畫布,客戶端不須要修改已經有的代碼,只須要在須要調用的地方添加便可 - (void)viewDidLoad{ CanvasViewGenerator *defaultGenerator = [[ClothCanvasViewGenerator alloc]init]; CanvasView *aCanvasView = [self loadCanvasViewWithGenerator:defaultGenerator]; } - (void)loadCanvasViewWithGenerator:(CanvasViewGenerator *)generator{ [canvasView_ removeFromSuperView]; CGRect aFrame = CGRectMake(0,0,320,436); CanvasView *aCanvasView = [generator canvasViewWithFrame:aFrame]; [self setCanvasView:aCanvasView]; [self.view addSubview:aCanvasView]; }
抽象工廠:提供一個建立一系列相關或互相依賴對象的接口,而無需指定他們具體的類。
簡單工廠,工廠方法,抽象工廠方法的區別
http://www.cnblogs.com/zhangchenliang/p/3700820.html
生成器:將一個複雜對象的構建和表現分離,相同的構建能夠建立不一樣的表現。
第三部分 接口適配
適配器模式:將一個類的接口轉換爲客戶但願的另一個接口,適配器模式使得因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。
應用場景,
已有類接口與需求不匹配,
想要一個複用的類,該類可以與不兼容的其餘類寫做,
用塊語法實現適配器
橋接模式:將抽象部分與實現部分分類,使他們均可以獨立地變化
使用場景
抽象和實現均可以經過子類化獨立進行擴展
對抽象的實現進行修改不該影響客戶端代碼
若是每一個實現須要額外的子類以細化抽象,則說明有必要把他們分紅2個部分
想在帶有不一樣抽象接口的多個對象之間共享一個實現。
外觀:爲系統中的一組接口提供一個統一的接口,外觀定義了一個高層接口,讓子系統更易於使用。
汽車類,負責 啓動,加油等操做
#import <Foundation/Foundation.h> @interface Car : NSObject { } // ... - (void) releaseBrakes; - (void) changeGears; - (void) pressAccelerator; - (void) pressBrakes; - (void) releaseAccelerator; // ... @end #import "Car.h" @implementation Car - (void) releaseBrakes { } - (void) changeGears { } - (void) pressAccelerator { } - (void) pressBrakes { } - (void) releaseAccelerator { }
計價器,負責計算價格
#import <Foundation/Foundation.h> @interface Taximeter : NSObject { } - (void) start; - (void) stop; @end #import "Taximeter.h" @implementation Taximeter - (void) start { } - (void) stop { } @end
司機類,負責開車和計價,可是給客戶端調用的時候提供了惟一的方法 - (void) driveToLocation:(CGPoint) x;方便客戶端調用
#import "Taximeter.h" @implementation Taximeter - (void) start { } - (void) stop { } @end #import "CabDriver.h" @implementation CabDriver - (void) driveToLocation:(CGPoint) x { // ... // set off the taximeter Taximeter *meter = [[Taximeter alloc] init]; [meter start]; // operate the vehicle // until location x is reached Car *car = [[Car alloc] init]; [car releaseBrakes]; [car changeGears]; [car pressAccelerator]; // ... // when it's reached location x // then stop the car and taximeter [car releaseAccelerator]; [car pressBrakes]; [meter stop]; // ... } @end
CabDriver *cab = [[CabDriver alloc]init];
[cab driveToLocation:CGPointMake(100, 100)];
中介者模式,用一個對象來封裝一系列對象的交互方式。中介者使各對象不須要互相飲用,從而使其耦合鬆散,並且能夠獨立地改變他們之間的交互。
使用場景:對象之間的交互雖然定義明確然而很是複雜,致使一組對象彼此互相依賴
由於對象引用了許多其餘對象並與其通信,致使對象難以複用
想要定製一個分部在多個類的邏輯或行爲,又不想生成太多子類
觀察者模式:定義對象見的一種一對多的依賴關係,當一個對象的狀態發生改變時,依賴於他的對象都獲得通知並被自動更新。
使用場景:
有2種抽象類型互相依賴,將它們封裝在各自的對象中,就能夠對它們單獨進行改變和複用
對一個對象的改變須要同時改變其餘對象,而不知道具體有多少對象有待改變
一個對象必須通知其餘對象,而它又不知道其餘對象是什麼。
通知 和鍵值觀察實現了觀察者模式
組合模式:將對象組合成樹狀結構以標示 部分-總體的層次結構,組合使得用戶對單個對象和組合對象的使用具備一致性。
使用場景:
想得到對象抽象的樹形表示
想讓客戶端統一處理組合結構中的全部對象
Cocoa Touch中的UIView 就是一個層次結構的例子。
迭代器:提供一種方法順序訪問一個聚合對象中的各元素,而又不需暴露該對象的內部表示。
使用場景:須要訪問組合對象的內容,而又不需暴露其內部表示
須要經過多種方式遍歷組合對象
須要提供一個統一的接口,用來便利各類類型的組合對象。
NSEnumerator實現了迭代器模式。可以順序遍歷各類集合
快速枚舉 forin,使用了指針運算
NSArray有個方法(void)makeObjectsPerformSelector:(SEL)aSelector;
訪問者模式:表示一個做用於某對象結構中的各元素的操做,它讓咱們能夠在不改變各元素的類的前提下定義做用於這些元素的新操做。
應用場景:一個複雜的對象結構包含不少其它對象,它們有不一樣的接口(好比組合體),這些對象實施一些依賴於其它類型的操做。
須要對一個組合結構中的對象進行不少不相關的操做,可是不想讓這些操做污染這些對象的類。能夠將相關的操做集中起來,定義在一個訪問者類中,並在須要在訪問者中定義的操做時使用它。
定義複雜結構的類不多做修改,但常常須要向其添加新的操做。
裝飾模式:動態地給一個對象添加一些額外的職責,就擴展功能來講,裝飾模式相比生成子類更爲靈活。
想要在不影響其它對象的狀況下,以動態,透明的方式給耽擱對象添加職責。
想要擴展一個類的行爲,卻作不到。類定義可能被隱藏,沒法進行子類化,或者,對類的每一個行爲的擴展,爲支持每種功能的組合將產生大量的子類。
對類的職責的擴展是可選的。
能夠經過 forwardingTargetForSelector:(SEL)aSelector 的方法或者
能夠經過範疇實現裝飾模式
定義基類的變化擴展類
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface UIImage (BaseFilter) - (CGContextRef) beginContext; - (UIImage *) getImageFromCurrentImageContext; - (void) endContext; @end #import "UIImage+BaseFilter.h" @implementation UIImage (BaseFilter) - (CGContextRef) beginContext { // Create a graphics context with the target size // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions // to take the scale into consideration // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext CGSize size = [self size]; if (NULL != UIGraphicsBeginImageContextWithOptions) UIGraphicsBeginImageContextWithOptions(size, NO, 0); else UIGraphicsBeginImageContext(size); CGContextRef context = UIGraphicsGetCurrentContext(); return context; } - (UIImage *) getImageFromCurrentImageContext { [self drawAtPoint:CGPointZero]; // Retrieve the UIImage from the current context UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext(); return imageOut; } - (void) endContext { UIGraphicsEndImageContext(); }
更加具體的一個擴展
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface UIImage (Transform) - (UIImage *) imageWithTransform:(CGAffineTransform)transform; @end #import "UIImage+Transform.h" #import "UIImage+BaseFilter.h" @implementation UIImage (Transform) - (UIImage *) imageWithTransform:(CGAffineTransform)transform { CGContextRef context = [self beginContext]; // setup transformation CGContextConcatCTM(context, transform); // Draw the original image to the context UIImage *imageOut = [self getImageFromCurrentImageContext]; [self endContext]; return imageOut; } @end
責任鏈模式:使多個對象都有機會請求處理請求,從而避免請求的發送者何接收者之間發生耦合。此模式將這些對象連成一條鏈,並沿着這條鏈傳遞請求,直到有一個對象處理它爲止。
使用場景:有多個對象能夠處理請求,而處理程序直郵在運行時才能肯定。
向一組對象發出請求,而不想顯式指定處理請求的特定處理程序。
一個攻擊遊戲人物護甲的演示
攻擊基類(什麼也沒有。。。)
#import <Foundation/Foundation.h> @interface Attack : NSObject { } @end #import "Attack.h" @implementation Attack @end
護甲基類,有一個下一個處理者的屬性,基類中定義了處理攻擊的行爲,會調用下一個處理者的該方法
#import <Foundation/Foundation.h> #import "Attack.h" @interface AttackHandler : NSObject { @private AttackHandler *nextAttackHandler_; } @property (nonatomic, retain) AttackHandler *nextAttackHandler; - (void) handleAttack:(Attack *)attack; @end #import "AttackHandler.h" @implementation AttackHandler @synthesize nextAttackHandler=nextAttackHandler_; - (void) handleAttack:(Attack *)attack { [nextAttackHandler_ handleAttack:attack]; } @end
金屬護甲能夠識別處理SwordAttack,若是處理成功了,傷害再也不繼續傳遞
#import <Foundation/Foundation.h> #import "AttackHandler.h" @interface MetalArmor : AttackHandler { } // overridden method - (void) handleAttack:(Attack *)attack; @end #import "MetalArmor.h" #import "SwordAttack.h" @implementation MetalArmor - (void) handleAttack:(Attack *)attack { if ([attack isKindOfClass:[SwordAttack class]]) { // no damage beyond this armor NSLog(@"%@", @"No damage from a sword attack!"); } else { NSLog(@"I don't know this attack: %@", [attack class]); [super handleAttack:attack]; } } @end
水晶護甲能夠識別處理MagicFireAttack,若是處理成功了,傷害再也不繼續傳遞,若是不能處理繼續傳遞。
#import <Foundation/Foundation.h> #import "AttackHandler.h" @interface CrystalShield : AttackHandler { } // overridden method - (void) handleAttack:(Attack *)attack; @end #import "CrystalShield.h" #import "MagicFireAttack.h" @implementation CrystalShield - (void) handleAttack:(Attack *)attack { if ([attack isKindOfClass:[MagicFireAttack class]]) { // no damage beyond this shield NSLog(@"%@", @"No damage from a magic fire attack!"); } else { NSLog(@"I don't know this attack: %@", [attack class]); [super handleAttack:attack]; } } @end
遊戲人物,接收全部的傷害
#import <Foundation/Foundation.h> #import "AttackHandler.h" @interface Avatar : AttackHandler { } // overridden method - (void) handleAttack:(Attack *)attack; @end #import "Avatar.h" @implementation Avatar - (void) handleAttack:(Attack *)attack { // when an attack reaches this point, // I'm hit. // actual points taken off depends on // the type of attack. NSLog(@"Oh! I'm hit with a %@!", [attack class]); } @end
這個例子裏面的傷害實現類都是基本沒有內容的。。。
#import <Foundation/Foundation.h> #import "Attack.h" @interface SwordAttack : Attack { } @end #import "SwordAttack.h" @implementation SwordAttack @end #import <Foundation/Foundation.h> #import "Attack.h" @interface MagicFireAttack : Attack { } @end #import "MagicFireAttack.h" @implementation MagicFireAttack @end #import <Foundation/Foundation.h> #import "Attack.h" @interface LightningAttack : Attack { } @end #import "LightningAttack.h" @implementation LightningAttack @end
客戶端調用
- (void)viewDidLoad { [super viewDidLoad]; // create a new avatar AttackHandler *avatar = [[[Avatar alloc] init] autorelease]; // put it in metal armor AttackHandler *metalArmoredAvatar = [[[MetalArmor alloc] init] autorelease]; [metalArmoredAvatar setAttackHandler:avatar]; // then add a crytal shield // to the avatar who's in // a metal armor AttackHandler *superAvatar = [[[CrystalShield alloc] init] autorelease]; [superAvatar setAttackHandler:metalArmoredAvatar]; // ... some other actions // attack the avatar with // a sword Attack *swordAttack = [[[SwordAttack alloc] init] autorelease]; [superAvatar handleAttack:swordAttack]; // then attack the avatar with // magic fire Attack *magicFireAttack = [[[MagicFireAttack alloc] init] autorelease]; [superAvatar handleAttack:magicFireAttack]; // now there is a new attack // with lightning... Attack *lightningAttack = [[[LightningAttack alloc] init] autorelease]; [superAvatar handleAttack:lightningAttack]; // ... further actions }
模板方法:定義一個操做中算法的骨架,而將一些步驟延遲到子類種中,模板方法使子類能夠重定義算法的某些特定步驟而不改變該算法的結構。
使用場景:
須要一次性實現算法的不變部分,而將可變的行爲留給子類來實現。
子類的共同行爲應該被提取出來放到公共類中,以免代碼的重複。現有代碼的差異應該被分離爲新的操做。而後用一個調用這些新操做的木板方法來替換這些不一樣的代碼。
須要控制子類的擴展。能夠定義一個在特定點調用鉤子操做的模板方法。子類能夠經過對鉤子操做的實如今這些點擴展功能。
製做三明治的例子來講
定義抽象基類,製做三明治的通常步驟
//AnySandwich.h #import <Foundation/Foundation.h> @interface AnySandwich : NSObject { } - (void) make; // Steps to make a sandwich - (void) prepareBread; - (void) putBreadOnPlate; - (void) addMeat; - (void) addCondiments; - (void) extraStep; - (void) serve; @end //AnySandwich.m #import "AnySandwich.h" @implementation AnySandwich - (void) make { [self prepareBread]; [self putBreadOnPlate]; [self addMeat]; [self addCondiments]; [self extraStep]; [self serve]; } - (void) putBreadOnPlate { // We need first to put bread on a plate for any sandwich. } - (void) serve { // Any sandwich will be served eventually. } #pragma mark - #pragma Details will be handled by subclasses - (void) prepareBread { [NSException raise:NSInternalInconsistencyException format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; } - (void) addMeat { [NSException raise:NSInternalInconsistencyException format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; } - (void) addCondiments { [NSException raise:NSInternalInconsistencyException format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; } - (void) extraStep{} @end
漢堡類
//Hamburger.h #import <Foundation/Foundation.h> #import "AnySandwich.h" @interface Hamburger : AnySandwich { } - (void) prepareBread; - (void) addMeat; - (void) addCondiments; //- (void) extraStep; // Hamburger specific methods - (void) getBurgerBun; - (void) addKetchup; - (void) addMustard; - (void) addBeefPatty; - (void) addCheese; - (void) addPickles; @end //Hamburger.m #import "Hamburger.h" @implementation Hamburger - (void) prepareBread; { [self getBurgerBun]; } - (void) addMeat { [self addBeefPatty]; } - (void) addCondiments { [self addKetchup]; [self addMustard]; [self addCheese]; [self addPickles]; } #pragma mark - #pragma mark Hamburger Specific Methods - (void) getBurgerBun { // A hamburger needs a bun. } - (void) addKetchup { // Before adding anything to a bun, we need to put ketchup. } - (void) addMustard { // Then add some mustard. } - (void) addBeefPatty { // A piece of beef patty is the main character in a burger. } - (void) addCheese { // Let's just assume every burger has cheese. } - (void) addPickles { // Then finally add some pickles to it. } @end
熱狗類
//Hotdog.h #import <Foundation/Foundation.h> #import "AnySandwich.h" @interface Hotdog : AnySandwich { } - (void) prepareBread; - (void) addMeat; - (void) addCondiments; //- (void) extraStep; // Hotdog specific methods - (void) getHotdogBun; - (void) addWiener; - (void) addKetchup; - (void) addMustard; - (void) addOnion; @end //Hotdog.m #import "Hotdog.h" @implementation Hotdog - (void) prepareBread { [self getHotdogBun]; } - (void) addMeat { [self addWiener]; } - (void) addCondiments { [self addKetchup]; [self addMustard]; [self addOnion]; } #pragma mark - #pragma mark Hotdog Specific Methods - (void) getHotdogBun { // First of all, we need a hotdog bun. } - (void) addWiener { // A nice piece of wiener is the main character here. } - (void) addKetchup { // Every hotdog needs ketchup. } - (void) addMustard { // I think mustard is also needed. } - (void) addOnion { // I think adding onion is a good idea. } @end
策略模式:定義一系列的算法,把它們一個個封裝起來,而且使它們可互相替換。本模式使得算法可獨立於使用它的客戶而變化。
一個類在其操做中使用多個條件語句來定義許多行爲。咱們能夠把相關的條件分支移到它們本身的策略類種功能。
須要算法的各類變體
須要避免把複雜的與算法相關的數據結構暴露給客戶端。
- (BOOL)validateInput:(UITextField *)input error:(NSError **)error;
採用error參數能夠傳遞錯誤信息,引用UITextField參數能夠對輸入框做相應的修改。
- (BOOL)validateInput:(UITextField*)input error:(NSError **)error{ NSError *regError = nil; NSRegularExpression *regx = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:®Error]; NSUInteger numberOfMatches = [regx numberOfMatchesInString:[input text] options:NSMatchingAnchored range:NSMakeRange(0, [[input text]length])]; if (numberOfMatches == 0) { if (error != nil) { NSString *description = NSLocalizedString(@"Input Validation Failed", @"") ; NSString *reason = NSLocalizedString(@"The input can contain only numberic values", @"") ; NSArray *objArray = [NSArray arrayWithObjects:description,reason, nil]; NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey,NSLocalizedFailureReasonErrorKey, nil]; NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray]; *error = [NSError errorWithDomain:@"InptValidationErrorDomain" code:1001 userInfo:userInfo]; } return NO; } return YES; }
若是直接調用漢堡的基類,會報錯
//不能夠直接調用抽象基類,會報錯 AnySandwich * sandwich = [[AnySandwich alloc] init]; [sandwich make]; //具體的子類能夠直接調用 AnySandwich *hotdog = [[Hotdog alloc]init]; [hotdog make];
命令模式:將請求封裝爲一個對象,從而可用不一樣的請求對客戶進行參數化,對請求排隊或記錄請求日誌,以及支持可撤銷的操做。
想讓應用程序支持撤銷與恢復。
想用對象參數話一個動做以執行操做,並用不一樣命令對象來代替回調函數。
想要在不一樣的時刻對請求進行指定,排序和執行。
想記錄修改日日誌,這樣在系統故障時,這些修改可在後來重作一遍。
想讓系統支持事務,事務封裝了對數據的一系列修改。事務能夠建模爲命令對象。
NSInvocation
NSUndoManager
享元模式(Flyweight pattern): 運用共享技術有效地支持大量細粒度的對象。
當知足全部條件時,天然會考慮使用這個模式:
應用程序使用不少對象
在內存中保存對象會影響內存性能
對象的多數特有狀態能夠放到外部而輕量化
移除外在狀態後,能夠用較少的共享對象替代原來的那組對象。
應用程序不依賴於對象標識,由於共享對象不能提供惟一的標識。
百花池 效果
定義了一個FlowerView用來展現花朵
//FlowerView.h 文件 #import <Foundation/Foundation.h> #import "UIKit/UIKit.h" @interface FlowerView : UIImageView @end //FlowerView.m 文件 #import "FlowerView.h" @implementation FlowerView - (void) drawRect:(CGRect)rect { [self.image drawInRect:rect]; } @end
定義了一個工廠方法來產生FlowerView
//FlowerFactory.h #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> typedef enum { kAnemone, kCosmos, kGerberas, kHollyhock, kJasmine, kZinnia, kTotalNumberOfFlowerTypes } FlowerType; @interface FlowerFactory : NSObject { @private NSMutableDictionary *flowerPool_; } - (UIView *) flowerViewWithType:(FlowerType)type; @end //FlowerFactory.m #import "FlowerFactory.h" #import "FlowerView.h" @implementation FlowerFactory - (UIView *) flowerViewWithType:(FlowerType)type { // lazy-load a flower pool if (flowerPool_ == nil) { flowerPool_ = [[NSMutableDictionary alloc] initWithCapacity:kTotalNumberOfFlowerTypes]; } // try to retrieve a flower // from the pool UIView *flowerView = [flowerPool_ objectForKey:[NSNumber numberWithInt:type]]; // if the type requested // is not available then // create a new one and // add it to the pool if (flowerView == nil) { UIImage *flowerImage; switch (type) { case kAnemone: flowerImage = [UIImage imageNamed:@"anemone.png"]; break; case kCosmos: flowerImage = [UIImage imageNamed:@"cosmos.png"]; break; case kGerberas: flowerImage = [UIImage imageNamed:@"gerberas.png"]; break; case kHollyhock: flowerImage = [UIImage imageNamed:@"hollyhock.png"]; break; case kJasmine: flowerImage = [UIImage imageNamed:@"jasmine.png"]; break; case kZinnia: flowerImage = [UIImage imageNamed:@"zinnia.png"]; break; default: break; } flowerView = [[FlowerView alloc] initWithImage:flowerImage]; [flowerPool_ setObject:flowerView forKey:[NSNumber numberWithInt:type]]; } return flowerView; }
保存flowerview的狀態
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface ExtrinsicFlowerState : NSObject @property (nonatomic,strong) UIView *flowerView; @property (nonatomic,assign) CGRect area; @end #import "ExtrinsicFlowerState.h" @implementation ExtrinsicFlowerState @end
控制器中調用代碼
- (void)viewDidLoad { [super viewDidLoad]; // construct a flower list FlowerFactory *factory = [[FlowerFactory alloc] init]; NSMutableArray *flowerList = [[NSMutableArray alloc] initWithCapacity:500]; for (int i = 0; i < 5000; ++i) { // retrieve a shared instance // of a flower flyweight object // from a flower factory with a // random flower type FlowerType flowerType = arc4random() % kTotalNumberOfFlowerTypes; UIView *flowerView = [factory flowerViewWithType:flowerType]; // set up a location and an area for the flower // to display onscreen CGRect screenBounds = [[UIScreen mainScreen] bounds]; CGFloat x = (arc4random() % (NSInteger)screenBounds.size.width); CGFloat y = (arc4random() % (NSInteger)screenBounds.size.height); NSInteger minSize = 10; NSInteger maxSize = 50; CGFloat size = (arc4random() % (maxSize - minSize + 1)) + minSize; // assign attributes for a flower // to an extrinsic state object ExtrinsicFlowerState * extrinsicState =[[ ExtrinsicFlowerState alloc]init]; extrinsicState.flowerView = flowerView; extrinsicState.area = CGRectMake(x, y, size, size); // add an extrinsic flower state // to the flower list [flowerList addObject: extrinsicState ]; } // add the flower list to // this FlyweightView instance FlyweightView *flyWeightView = [[FlyweightView alloc]initWithFrame:CGRectMake(0, 0, 320, 640)]; flyWeightView.backgroundColor = [UIColor orangeColor]; [flyWeightView setFlowerList:flowerList]; [self.view addSubview:flyWeightView]; // Do any additional setup after loading the view, typically from a nib. }
這樣處理比直接在self.view 上添加 UIImageView仍是節約了不少內存開銷的,效果以下
代理模式:爲其它對象提供一種代理以控制對這個對象的訪問。
須要一個遠程代理,爲處於不一樣地質空間或者網絡中的對象提供本地帶遍。
須要一個虛擬代理,爲根據要求建立重型的對象。
須要一個保護代理,來控制不一樣訪問權限對原對象的訪問。
須要一個智能引用代理,經過對實體對象的引用來進行計數來管理內存。也能用戶鎖定實體對象,讓其它對象不能修改它。
備忘錄模式:在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣之後就可將該對象恢復到原來保存的狀態。
Cocoa Touch NSKeyedArchiver NSKeyedUnarchiver
NSCoding 協議
參考資料
Pro Objective C Design Pattern for iOS Objective C編程之道iOS設計模式解析
https://github.com/iossvis/Objective-C-Design-Patterns-for-IOS----Carlo-Chung-book-s-code