裝潢器形式可以在不修正代碼的情形下靈巧的為一對象添加行動和職責。當你要修正一個被其它類包括的類的行動時,它可以取代子類化辦法。
1、根本完成
上面我把類的構造圖向年夜家展現以下:
讓我們簡略剖析一下下面的構造圖,Component是界說一個對象接口,可以給這些對象靜態地添加職責。ConcreteComponent是界說了一個詳細的對象,也能夠給這個對象添加一些職責。Decorator,裝潢籠統類,繼續了Component,從外類來擴大Component類的功效,但關於Component來講,是無需曉得Decorator的存在的。至於ConcreteDecorator就是詳細的裝潢對象,起到給Component添加職責的功效。
上面,照樣老套路,我會盡量的給出Objective C完成的最簡略的實例代碼,起首聲明一下,這些代碼是運轉在ARC情況下的,所以關於某些能夠惹起內存洩露的資本並沒有采取手動釋放的方法,這一點照樣須要年夜家留意。
留意:本文一切代碼均在ARC情況下編譯經由過程。
Components類接口文件
#import<Foundation/Foundation.h>
@interface Components :NSObject
-(void) Operation;
@end
Components類完成文件
#import"Components.h"
@implementation Components
-(void)Operation{
return;
}
@end
Decorator類接口文件
#import"Components.h"
@interface Decorator :Components{
@protected Components *components;
}
-(void)SetComponents:(Components*)component;
@end
Decorator類完成文件
#import"Decorator.h"
@implementation Decorator
-(void)SetComponents:(Components*)component{
components = component;
}
-(void)Operation{
if(components!=nil){
[components Operation];
}
}
@end
ConcreteComponent類接口文件
#import"Components.h"
@interface ConcreteComponent :Components
@end
ConcreteComponent類完成文件
#import "ConcreteComponent.h"
@implementation ConcreteComponent
-(void)Operation{
NSLog(@"詳細操作的對象");
}
@end
ConcreteDecoratorA類接口文件
#import "ConcreteDecoratorA.h"
#import "Decorator.h"
@interface ConcreteDecoratorA :Decorator
@end
ConcreteDecoratorA類完成文件
#import"ConcreteDecoratorA.h"
@implementation ConcreteDecoratorA
-(void)Operation{
NSLog(@"詳細裝潢對象A的操作");
[super Operation];
}
@end
ConcreteDecoratorB類接口文件
#import "Decorator.h"
@interface ConcreteDecoratorB :Decorator
@end
ConcreteDecoratorB類完成文件
#import "ConcreteDecoratorB.h"
@implementation ConcreteDecoratorB
-(void)Operation{
NSLog(@"詳細裝潢對象B的操作");
[super Operation];
}
@end
Main辦法
#import <Foundation/Foundation.h>
#import "ConcreteComponent.h"
#import "ConcreteDecoratorA.h"
#import "ConcreteDecoratorB.h"
int main (int argc,const char* argv[])
{
@autoreleasepool{
ConcreteComponent *c = [[ConcreteComponent alloc]init];
ConcreteDecoratorA *d1 = [[ConcreteDecoratorA alloc]init];
ConcreteDecoratorB *d2 = [[ConcreteDecoratorB alloc]init];
[d1 SetComponents:c];
[d2 SetComponents:d1];
[d2 Operation];
}
return 0;
}
好啦,下面是須要展現的類,語法上都很簡略,沒有甚麼須要重點說的,能夠值得一提的是關於子類挪用父類辦法的常識點,就是在挪用每一個對象的Operation辦法的時刻,外面會有一句代碼是[super Operation];這句代碼構很症結,他組成了各個對象之間Operation辦法的跳轉,以此完成對Components類對象的”裝潢”。
2、分類(Category)和拜托(Delegation)
在 Object-C 裡有兩個種異常罕見的完成形式:分類(Category)和拜托(Delegation)。
1.分類 Category
分類是一種異常壯大的機制,它許可你在一個已存在的類裡添加新辦法,而不須要去為他添加一個子類。新辦法在編譯的時刻添加,它能像這個類的擴大辦法一樣正常履行。一個裝潢器跟類的界說略微有點分歧的就是,由於裝潢器不克不及被實例化,它只是一個擴大。
提醒:除你本身類的擴大,你還可在任何 Cocoa 類裡的擴大添加辦法。
若何應用分類:
如今你有一個 Album 對象,你須要把它顯示在一個表單視圖裡(table view):
專輯的題目從哪裡來?Album 只是一個模子對象,它才不會去關懷你假如去顯示這些數據。為了這些,你須要給 Album 類添加一些額定的代碼,然則請不要直接修正這個類。
你如今就須要為 Album 添加一個分類 (category) 的擴大;它將界說一個新處所法用來前往一個數據構造,這個數據構造可以很輕易的被 UITableViews 應用。
這個數據構造看起來以下:
為 Album 添加一個分類,導航 File\New\File… 選擇 Object-C category 模版─不要習氣的去選擇 Object-C class,在 Category 前面輸出 TableRepresentation,Category to 前面輸出 Album。
提醒:你有無留意這個新文件的名字?Album+TableRepresentation 解釋它是 Album 類的一個擴大。這個習氣很主要,由於第一這很輕易讀,第二避免你或許其別人創立的分類跟其抵觸。
翻開 Album+TableRepresentation,參加上面的辦法原型:
- (NSDictionary*)tr_tableRepresentation;
留意,這是一個 tr_ 開首的辦法名,就像是這個分類名字的縮寫一樣:TableRepresentation。其次,這個習氣會防止這個辦法跟其它辦法重名!
提醒:假如分類 (Category) 聲明的一個辦法跟原始類的一個辦法重名,或許跟同類裡的的另外一個分類名字反復(或許是它的父類),當它在運轉的時刻,它就不曉得要履行哪一個辦法。假如是在你本身類的分類裡,它不太能夠湧現年夜的成績,然則假如一個尺度 Cocoa 或許 Cocoa Touch 類外面添加這個分類的辦法,便可能會惹起嚴重的成績。
翻開 Album+TableRepersentation.m 文件添加上面的辦法:
- (NSDictionary*)tr_TableRepersentation
{
return @{@"titles":@[@"Artist", @"Album", @"Genre", @"Year"],
@"values":@[self.artist, self.title, self.genre, self.year]};
};
斟酌一會,為何這類形式如些壯大:
你可以或許直接應用 Album 的屬性。
你曾經添加在 Album 類裡,但它其實不是它的子類。假如子類須要,你異樣也能夠如許做。
如許一個簡略的添加,Album 類的數據前往一個 UITableView 可用的數據構造,但其實不須要修正 Album 的代碼。
蘋果在基本類裡年夜量的應用了分類設計形式。去看看他們是怎樣做的,翻開 NSString.h。找到 @interface NSString,你將會看到這個類界說了三個分類:NSStringExtensionMethods, NSExtendedStringPropertyListParsing 和 NSStingDeprecated。在代碼片裡,分類將贊助你堅持辦法的組織性和分別必。
2.拜托 Delegation
別的一種裝潢器的設計形式是,拜托 (Delegation),它是一種機制,一個對象代表別的一個對象或許其互相協作。例子,當你應用 UITableView 的時刻,個中一個辦法是你必須要履行的,tableView:numberOfRowsInSection:。
你能夠其實不希冀 UITableView 曉得每一個 section 中有若干行,這是法式的特征。是以,盤算每一個 section 有若干行的任務就交給了 UITableView 的拜托 (delegate)。它許可 UITableView 類不依附它顯示的數據。
當你創立了一個新的 UITableView 的時刻,這裡有一個相似的說明:
UITableView 對象的任務就是顯示一個表單視圖。但是,終究它都須要一些它信息,它其實不具有這些信息。然後,它會轉向它的拜托,發送一個添加信息的新聞。在 Object-C 中完成拜托形式,一個類可以經由過程協定 (protocol) 來聲明一個可選和必選的辦法。稍後,在這個教程你將籠罩一個協定 (protocols)。
它看起來比子類更輕易,籠罩須要的辦法,然則斟酌假如是單類的話你只能創立子類。假如你想一個對象拜托兩個或許多個對象的時刻,子類化的辦法是不克不及完成的。
提醒:這是一個很主要的形式。蘋果在 UIKit 類中年夜量的應用了此辦法:UITableView, UITextView, UITextField, UIWebView, UIAlert, UIActionSheet, UICollectionView, UIPickerView, UIGestureRecognizer, UIScrollView。這個列表還可以有許多。
若何應用拜托形式:
翻開 ViewController.m,在頂部引入以下文件
#import "LibraryAPI.h"
#import "Album+TableRepresentation.h"
如今,在類的擴大裡的添加一些公有變量,它們看起來以下:
@interface ViewController (){
UITableView *dataTable;
NSArray *allAlbums;
NSDictionary *currentAlbumData;
int currentAlbumIndex;
}
@end
如今,調換類擴大裡的 @interface 這一行,完成後以下:
@interface ViewController () <UITableViewDataSoure, UITableViewDelegate> {
這就是若何設置一個准確的拜托─把它相象成許可一個拜托來實行一個辦法的合同。這裡,注解 ViewController 將會遵守 UITableViewDataSource 和 UITableViewDelegate 協定。這類辦法下 UITableView 必需履行它本身的拜托辦法。
上面,用上面的代碼調換 viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
// 1
self.view.backgroundColor = [UIColor colorWithRed:0.76f green:0.81f blue:0.87f alpha:1];
currentAlbumIndex = 0;
//2
allAlbums = [[LibraryAPI sharedInstance] getAlbums];
// 3
// the uitableview that presents the album data
dataTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 120, self.view.frame.size.width, self.view.frame.size.height-120) style:UITableViewStyleGrouped];
dataTable.delegate = self;
dataTable.dataSource = self;
dataTable.backgroundView = nil;
[self.view addSubview:dataTable];
}
這裡剖析下下面的代碼:
把配景色改成英俊的深藍色。
從 API 獲得一個列表,它包括一切的專輯數據。不克不及直接應用 PersistencyManager。
創立一個 UITableView。你聲清楚明了視圖掌握器是 UITableView delegate/data source;是以,UITableView 將會供給視圖掌握器須要的一切信息。
如今,在 ViewController.m 外面添加以下辦法:
- (void)showDataForAlbumAtIndex:(int)albumIndex{
// defensive code: make sure the requested index is lower than the amount of albums
if (albumIndex < allAlbums.count) {
// fetch the album
Album *album = allAlbums[albumIndex];
// save the albums data to present it later in the tableview
currentAlbumData = [album tr_tableRepresentation];
} else {
currentAlbumData = nil;
}
// we have the data we need, let's refresh our tableview
[dataTable reloaddata];
}
showDataForAlbumAtIndex: 從專輯數組中掏出須要的專輯數據。當你須要顯示新數據的時刻,你只須要重載數據 (relaodData)。這是由於 UITableView 須要要求它的拜托署理,像有若干 sections 將會在表單視圖中顯示,每一個 section 中有若干行,每行看起來是甚麼樣的。
在 viewDidLoad 中添加上面代碼
[self showDataForAlbumAtIndex:currentAlbumIndex];
當法式運轉的時刻它會加載以後的專輯信息。因為 currentAlbumIndex 的預設值為 0,所以會顯示珍藏中的第一張專輯信息。
構建並運轉你的項目,你的法式會瓦解失落,在掌握台會輸出以下的異常:
湧現甚麼成績了?你曾經聲清楚明了 ViewController 中的 UItableView 的拜托(delegate)和數據源(data source)。然則在這類情形下,你必須履行一切的必須辦法─包括 tableView:numberOfRowsInsection:─你如今還沒有它。
在 ViewContrller.m 的 @implementation 和 @end 的任何處所添加以下代碼:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [currentAlbumData[@"titles"] count];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
}
cell.textLabel.text = currentAlbumData[@"titles"][indexPath.row];
cell.detailTextLabel.text = currentAlbumData[@"values"][indexPath.row];
return cell;
}
tableView:numberOfRowsIndexSection: 前往表單視圖顯示的行數,婚配數據構造中題目的數量。
tableView:cellForRowAtIndexPath: 創立並前往一個帶題目和信息的 cell。
如今構建並運轉你的項目。你的法式開端運轉並顯示出下圖的界面:
這今朝為止工作看起來很不錯。然則假如你回曩昔看第一張圖片的時刻,你會發明在屏幕的頂端有一個可以程度轉動的視圖,用於切換專輯。它只是簡略的程度轉動,為何不做一個可以反復應用的視圖來取代它呢。
【深刻解析設計形式中的裝潢器形式在iOS運用開辟中的完成】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!