有三我的分別要去A、B、C三個地方,因爲目的地比較遠,他們分別駕駛了三輛車到達目的地。 編程
若是要去100個目的地,每一個目的地派遣1輛車,那麼總計須要100輛車。
好比北上廣深等一線城市天天幾千萬次出行,沒人一輛車城市不就癱瘓了嘛。。。。設計模式
因此,如何解決呢?數組
經過分析,其實咱們不難發現2個規律:服務器
1. 去任意地方的交通工具是相同的 2. 不一樣的是目的地位置
經過開設公共交通來設置多個車站,讓大量去往相同方向的乘客分擔保有和經營車輛的費用。
乘客沿着路線在接近他們目的地的地方上下車。達到目的地的費用僅與行程有關。
跟保有車輛相比,乘坐公共交通更便宜,這就是利用公共資源的好處。數據結構
圍棋棋盤理論上有361個空位能夠放棋子,那若是用常規的面向對象方式編程,每局棋可能有兩三百個棋子對象產生。
若是有一臺服務器爲玩家提供在線遊戲,這樣可能很難支持更多的玩家同時參與了,畢竟內存空間是有限的。dom
一個完整的棋子包括: 棋子自己(黑/白) + 棋盤座標
工具
咱們只要2個棋子就夠了,在外部保存一個數組存儲座標信息。
使用時,咱們只需根據key(黑、白)取到對應的棋子,而後把座標信息傳遞給棋子,這樣咱們就獲得對應完整棋子對象。性能
具體看一下享元模式是如何描述的:atom
享元模式: 運用共享技術有效地支持大量細粒度的對象。
先看一下靜態類圖:spa
在享元模式結構圖中包含以下幾個角色:
這裏以iOS的一個小項目爲例:
在屏幕上隨機顯示花朵圖案,圖案的類型、位置、大小都是隨機生成,並且讓這些花朵可以撲滿屏幕。
下面是給出的花朵樣式:
隨機生成200個花朵圖案的效果大約是這樣:
上面給出了6種花朵圖案,讓每一種圖案由一個惟一的FlowerView的實例來維護,而與須要的花朵總數無關。下面是它們的靜態關係圖:
FlowerView是UIImageView的子類,用它繪製一朵花朵圖案。FlowerFactory是享元工廠類,它管理一個FlowerView實例的池。
儘管工廠池中對象是FlowerView,但要求FlowerFactory返回UIView的實例。與讓工廠直接返回UIImage類型的最終產品相比,這樣的設計更靈活。由於有時候咱們可能須要自定義繪製其它的圖案,而不僅是顯示固定的圖像。
UIView是任何須要在屏幕上繪圖的最高抽象。FlowerFactory能夠返回任何UIView子類對象,而不會破壞系統。這就是針對接口編程,而不是針對實現編程
的好處。
FlowerFactory用flowerPool聚合了一個花朵池的引用。flowerPool是一個保存FlowerView的全部實例的數據結構。
FlowerFactory經過flowerViewWithType: 方法返回FlowerView實例。
若是池子中沒有所請求花朵的類型,就會建立一個新的FlowView實例返回,並保存到池子中。
它是UIImageView的子類,代碼比較簡單
@interface FlowerView : UIImageView @end @implementation FlowerView - (void)drawRect:(CGRect)rect { [self.image drawInRect:rect]; } @end
typedef NS_ENUM(NSInteger, FlowerType) { kAnemone = 0, kCosmos, kGerberas, kHollyhock, kJasmine, kZinnia, kTotalNumberOfFlowTypes, }; @interface FlowerFactory : NSObject - (UIView *)flowerViewWithType:(FlowerType)type; @end @interface FlowerFactory () @property (nonatomic, strong) NSMutableDictionary *flowerPool; @end @implementation FlowerFactory - (UIView *)flowerViewWithType:(FlowerType)type { FlowerView *flowerView = [self.flowerPool objectForKey:@(type)]; if (nil == flowerView) { UIImage *image = nil; switch (type) { case kAnemone: image = [UIImage imageNamed:@"anemone"]; break; case kCosmos: image = [UIImage imageNamed:@"cosmos"]; break; case kGerberas: image = [UIImage imageNamed:@"gerberas"]; break; case kHollyhock: image = [UIImage imageNamed:@"hollyhock"]; break; case kJasmine: image = [UIImage imageNamed:@"jasmine"]; break; case kZinnia: image = [UIImage imageNamed:@"zinnia"]; break; default: break; } flowerView = [[FlowerView alloc] init]; flowerView.image = image; [self.flowerPool setObject:flowerView forKey:@(type)]; } return flowerView; } - (NSMutableDictionary *)flowerPool { if (_flowerPool == nil) { _flowerPool = [NSMutableDictionary dictionaryWithCapacity:7]; } return _flowerPool; } @end
享元對象老是和某種可共享的內在狀態聯繫在一塊兒,儘管並不徹底如此,可是咱們的FlowerView享元對象確實共享了做爲其內在狀態的內部花朵圖案。無論享元對象是否有可供共享的內在狀態,任然須要定義某種外部的數據結構,保存享元對象的外在狀態。
每朵花都有各自的顯示區域,因此這須要做爲外在狀態來處理。
這裏特此定義了一個C結構體ExtrinsicFlowerState。
struct ExtrinsicFlowerState { __unsafe_unretained UIView *flowerView; CGRect area; };
咱們把最終生成的全部花朵實例都填充到FlowerContainerView視圖上
@interface FlowerContainerView : UIView @property (nonatomic, copy) NSArray *flowerList; @end @implementation FlowerContainerView - (void)drawRect:(CGRect)rect { for (NSValue *stateValue in self.flowerList) { struct ExtrinsicFlowerState flowerState; [stateValue getValue:&flowerState]; UIView *flowerView = flowerState.flowerView; CGRect frame = flowerState.area; [flowerView drawRect:frame]; } } @end
在rootViewController的viewDidLoad 方法中調用
#define kFlowerListCount 200 @interface ViewController () @property (nonatomic, strong) FlowerFactory *flowerFactory; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; FlowerContainerView *flowerContainer = [[FlowerContainerView alloc] initWithFrame:self.view.bounds]; flowerContainer.backgroundColor = [UIColor whiteColor]; [self.view addSubview:flowerContainer]; FlowerFactory *factory = [[FlowerFactory alloc] init]; self.flowerFactory = factory; NSMutableArray *flowerList = [NSMutableArray arrayWithCapacity:kFlowerListCount];; for (NSInteger i = 0; i < kFlowerListCount; i++) { // 從花朵工廠取得一個共享的花朵享元對象實例 FlowerType type = arc4random() % kTotalNumberOfFlowTypes; UIView *flowerView = [factory flowerViewWithType:type]; // 設置花朵的顯示位置和區域 CGRect screenBounds = [[UIScreen mainScreen] bounds]; CGFloat x = arc4random() % (NSInteger)screenBounds.size.width; CGFloat y = arc4random() % (NSInteger)screenBounds.size.height; NSInteger minSize = 10; NSInteger maxSize = 60; CGFloat size = (arc4random() % (maxSize - minSize)) + minSize; // 把花朵參數存入一個外在對象 struct ExtrinsicFlowerState extrinsicState; extrinsicState.flowerView = flowerView; extrinsicState.area = CGRectMake(x, y, size, size); // 花朵外在狀態添加到花朵列表中 [flowerList addObject:[NSValue value:&extrinsicState withObjCType:@encode(struct ExtrinsicFlowerState)]]; } [flowerContainer setFlowerList:flowerList]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
源碼下載地址FlyweightDemo
享元模式是一個考慮系統性能的設計模式,經過使用享元模式能夠節約內存空間,提升系統的性能。
享元模式的核心在於享元工廠類,享元工廠類的做用在於提供一個用於存儲享元對象的享元池,用戶須要對象時,首先從享元池中獲取,若是享元池中不存在,則建立一個新的享元對象返回給用戶,並在享元池中保存該新增對象。
享元模式以共享的方式高效地支持大量的細粒度對象,享元對象能作到共享的關鍵是區份內部狀態(Internal State)和外部狀態(External State)。
在如下狀況下可使用享元模式:
享元模式的優勢
享元模式的缺點