有三我的分别要去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)。
在如下状况下可使用享元模式:
享元模式的优势
享元模式的缺点