蝇量模式(FlyWeight Pattern)
蝇量模式:如果想让某个类的一个实例,能提供很多的虚拟实例,那就使用蝇量模式
蝇量模式又称为享元模式属于结构型设计模式中的一种。
蝇量模式这个定义读起来并不算太清晰。让人摸头不知脑,确实最开始我看也是一脸懵逼。不过搞懂了它的定义就就发现这也是一个很简单的设计模式,当然绝大多数情况下可能我们很少会使用它。
蝇量在拳击中是最轻的两个重量级之一。个人理解是为了在创建较多对象的时候让对象更轻量,而采用的一种设计模式。
当选择创建对象的时候我们会为对象分配内存空间,如果对象过多,过大,会导致性能问题(内存,时间)。
蝇量模式通过一个管理对象创建多个虚拟的实例来减少实际对象的创建。
虚拟实例所需要的变量,参数由管理对象保存。虚拟实例只需要实现真实对象所需要实现的方法。并且有些公共的参数可以由管理对象提供,而不需要每个虚拟对象携带,这样来,可以节省大量的内存。
举个栗子
网上能找到很多种树,画花的栗子,这里我们也不能免俗,我们画花吧。毕竟UI上的渲染速度和内存消耗是很能考验一个设计的性能的。
这是花的实现
花直接绘制在layer上,这里只用来绘制花到具体的位置
#import <UIKit/UIKit.h>
#import "Flower.h"
@implementation Flower
-(void)drawWithContext:(CGContextRef)context rect:(CGRect)rect image:(UIImage *)image {
CGImageRef cgImage = CGImageRetain(image.CGImage);
CGContextDrawImage(context, rect, cgImage);
}
@end
对于花的维护和管理类,另外绘制图片本来就是一种展示不做其他交互,所以这里不保存任何数据。
#import "FlowerMangerView.h"
#import "Flower.h"
@interface FlowerMangerView()
@property (nonatomic ,strong)Flower * flower;
@end
@implementation FlowerMangerView
-(instancetype)init {
if (self = [super init]) {
_flower = [[Flower alloc] init];
}return self;
}
-(void)drawRect:(CGRect)rect {
CGContextRef ref = UIGraphicsGetCurrentContext();
for (int i = 0; i < 10000; i++) {
int x = arc4random() % 375;
int y = arc4random() % 1334;
int width = arc4random() % (375 - x);
int height = arc4random() % (1334 - y);
CGRect rect = CGRectMake(x, y, width, height);
[_flower drawWithContext:ref rect:rect image:[UIImage imageNamed:[NSString stringWithFormat:@"icon%d",i % 5]]];
}
}
@end
这里我拿项目内存做了下对比
空App大小为13.5M
蝇量模式 (10000 朵 花)App大小为17.7M
添加视图的方式(10000 朵 花)来处理的app大小为27.1M
很显然蝇量模式的内存增量微乎其微,而直接添加视图的方式导致内存猛增。
可能有人会觉得demo和展示的类图有区别,确实是这样。
UML图中提供了用工厂模式创建不同蝇量并分别存储在map 中。而示例需求由于太简单,使用工厂意义不大。但是并不能将demo示例不算作蝇量模式,UML图只是给我们开发过程一个参考,但是只要满足蝇量模式的定义都可以将该模式称作为蝇量模式。
优点
1.减少实例对象的创建,节省内存
2.将许多虚拟对象的状态集中管理
缺点
单个逻辑的实例,无法拥有独立而不同的行为。