在軟件設計中,如果客戶想手動創建一個對象,需要知道對象的詳細結構,包括其數據結構以及方法調用,如果運氣不好,還可能因為該對象引用了其他對象,導致客戶端還得了解其他對象,如此..使得該對象的創建變得復雜起來。之前講過的工廠方法模式可以解決該類問題,不過工廠方法模式一般用來解決單個對象的創建,對於需要創建多個有關聯的對象,那麼可能就需要使用抽象工廠模式的方法了。此時,客戶端只需要知道抽象出來的工廠以及自己所要的對象即可,不必清楚是誰創建以及怎樣創建那些具體的對象。
抽象工廠的具體定義為:抽象工廠提供固定的接口,用於創建一系列有關聯的對象,而不必指出其創建的細節。
ABSTRACT FACTORY: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.*
* The original definition appeared in Design Patterns, by the “Gang of Four” (Addison-Wesley,1994).
其類似的類圖示意圖可能如下所示
上述的類圖示意圖中,如果客戶端想創建產品A和B,他只需要知道抽象工廠的固定接口createProductA和createProductB(當然還得知道AbstractFactory、AbstractProductA和AbstractProductB的存在),這樣他就能夠直接使用這兩個接口創建自己所需要的產品A和B了,而不需要知道產品A和B是誰創建的,在哪創建以及其他細節問題。通過抽象工廠的封裝,使得有關聯的對象的創建變得透明、簡單化。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+tMvN4qOszai5/bPpz/O5pLOnxKPKvbXEseCzzLe9t6ijrMTjyOe5+7rz0PjP68ztvNPG5Mv7svrGt6Os1PLWsb3TsLTV1baousO1xLPpz/O5pLOnvdO/2sq1z9a8tL/Jo6y2+LK70OjSqrjEseS/zbuntsu1xLT6wuu199PDoaM8L3A+CjxwPtTa1eLA77u5tcOyubPk0ru147nY09q5pLOnt723qLrNs+nP87mks6e1xLnYz7XOyszio6zJz8281tCjrLPpz/O5pLOnysfT0LD8uqy5pLOnt723qLXEyei8xsSjyr21xKOsxuTW0GNyZWF0ZVByb2R1Y3RBus1jcmVhdGVQcm9kdWN0Qra8yvTT2rmks6e3vbeoo6y4/LbgtcSxyL3Pv8m8+8/Cse2jujwvcD4KPGJsb2NrcXVvdGU+CjxibG9ja3F1b3RlPgo8YmxvY2txdW90ZT4KPHA+Cjx0YWJsZSBib3JkZXI9"1" width="800" cellspacing="1" cellpadding="1">
還是用主題來做個例子吧,這個例子是一個界面主題,該主題包括三部分:主視圖,按鈕,工具欄,不同的主題,這些元素的樣式不一樣,其他的是一樣的。因此由此可抽象出一個抽象工廠類,該類提供的固定接口是三個創建對象的方法,分別用來創建主視圖、按鈕和工具欄。主要的關系圖如下所示:
抽象類的定義如下所示:
#import上述代碼定義了三個固定的接口,而類方法fatoryWithName則會根據名字選擇對應的工廠。其中三個固定接口在抽象工廠類返回值是nil,而其中的類方法其實現如下所示:#import @interface BrandFactory : NSObject + (BrandFactory*)fatoryWithName:(NSString*)name; - (UIView*) brandView; - (UIButton*) brandMainButton; - (UIToolbar*) brandToolbar; @end
+ (BrandFactory*)fatoryWithName:(NSString*)name { BrandFactory* factory = nil; if([name isEqualToString:@"Serra"]) { factory = [[SerraBrandFactory alloc] init]; } else if([name isEqualToString:@"Acme"]) { factory = [[AcmeBrandFactory alloc] init]; } return factory; }
對應於上圖的關系圖,實現的兩個具體工廠類如下所示:
@implementation SerraBrandFactory - (UIView*) brandView { UIView* view = [[UIView alloc] init]; view.backgroundColor = [UIColor redColor]; return view; } - (UIButton*) brandMainButton { UIButton* button = [[UIButton alloc] init]; [button setTitle:@"Serra" forState:UIControlStateNormal]; return button; } - (UIToolbar*) brandToolbar { UIToolbar* toolbar = [[UIToolbar alloc] init]; toolbar.barStyle = UIBarStyleBlack; UIBarButtonItem* item = [[UIBarButtonItem alloc] init]; [item setImage:[UIImage imageNamed:@"cat.png"]]; toolbar.items = [NSArray arrayWithObject:item]; return toolbar; } @end
@implementation AcmeBrandFactory - (UIView*) brandView { UIView* view = [[UIView alloc] init]; view.backgroundColor = [UIColor blueColor]; return view; } - (UIButton*) brandMainButton { UIButton* button = [[UIButton alloc] init]; [button setTitle:@"Acme" forState:UIControlStateNormal]; return button; } - (UIToolbar*) brandToolbar { UIToolbar* toolbar = [[UIToolbar alloc] init]; toolbar.barStyle = UIBarStyleBlack; UIBarButtonItem* item = [[UIBarButtonItem alloc] init]; [item setImage:[UIImage imageNamed:@"dog.png"]]; toolbar.items = [NSArray arrayWithObject:item]; return toolbar; } @end上兩個實現分別返回自身定制的產品對象,而且都是通過基類抽象工廠類的固定接口返回的,這樣當客戶端需要構建這些對象的時候,直接使用抽象工廠提供的接口即可完成對所需的對象的創建,客戶端凍得代碼調用如下所示:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 客戶端加載視圖 BrandFactory* brand = [BrandFactory fatoryWithName:@"Serra"]; //BrandFactory* brand = [BrandFactory fatoryWithName:@"Acme"]; UIView* brandView = [brand brandView]; brandView.frame = self.view.frame; [self.view addSubview:brandView]; UIButton* brandButton = [brand brandMainButton]; brandButton.frame = CGRectMake(60, 100, 200, 100); [self.view insertSubview:brandButton aboveSubview:brandView]; UIToolbar* brandToolbar = [brand brandToolbar]; brandToolbar.frame = CGRectMake(0, brandView.frame.size.height-40, brandView.frame.size.width, 40); [self.view insertSubview:brandToolbar aboveSubview:brandView]; }使用抽象工廠的設計模式後,通過工廠的封裝,客戶端不再需要知道產品的具體細節,實現內部的黑盒透明化,同時,如果新增了產品後,客戶端的代碼調用改動會很小,只需要指定名字即可。如果不適用抽象工廠,那麼常規的方法是這裡需要自己手動創建每個產品對象,需要了解產品的具體細節,同時如果要修改為其他產品的話,要修改大量代碼,可維護性和代碼的重用性大大降低。因此,抽象工廠模式是好的,工廠設計模式是好的。
抽象工廠以及其他的工廠模式是一種比較常見以及簡單的編程設計模式,他也是最基本的設計模式,因為他涉及到許多類型對象的創建。在創建對象的時候,最好使用設計模式封裝對象,使得對象抽象出來,具體細節得到隱藏。