享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
应用举例
创建不同种类的花。
第一步,创建花的工厂方法:
typedef enum {
kRedFlower, // 0
kBlueFlower, // 1
kYellowFlower, // 2
kTotalNumberFlower // 用于计数的.
}FlowerType;
@interface FlowerFactory : NSObject
// 缓存池, 存放享元对象
@property (nonatomic, strong) NSMutableDictionary *flowerPools;
// 创建花的工厂方法
- (Flower *)flowerViewWithType:(FlowerType)type;
- (void)detailsType;
@end
懒加载享元池,从享元池中取享元,如果有就返回,没有就新建,并添加到享元池里面,同时返回新建的享元。
@implementation FlowerFactory
- (Flower *)flowerViewWithType:(FlowerType)type {
// 1. 懒加载flowerPools, 初始化享元池.
if (self.flowerPools == nil) {
self.flowerPools = [[NSMutableDictionary alloc] initWithCapacity:kTotalNumberFlower];
}
// 2. 去享元池里面取
Flower *flower = [self.flowerPools objectForKey:[NSNumber numberWithInteger:type]];
// 3. 如果没取到就判断
if (flower == nil) {
// 1. 创建花
flower = [[Flower alloc] init];
// 2. 根据传进来的类型, 去选择对应的类型
switch (type) {
case kRedFlower:
flower.flowerColor = @"红色的花";
flower.flowerName = @"红玫瑰";
break;
case kBlueFlower:
flower.flowerColor = @"蓝色的花";
flower.flowerName = @"蓝玫瑰";
break;
case kYellowFlower:
flower.flowerColor = @"黄色的花";
flower.flowerName = @"野菊花";
break;
default:
break;
}
// 3. 把创建的话,添加到享元池里面
[self.flowerPools setObject:flower forKey:[NSNumber numberWithInt:type]];
}
return flower;
}
- (void)detailsType {
NSArray *array = [self.flowerPools allKeys];
// 打印
for (NSNumber *key in array) {
NSLog(@"di zhi = %@, key = %@", self.flowerPools[key], key);
}
}
@end
第二步,实例花的对象:
@interface Flower : NSObject
@property (nonatomic, copy) NSString *flowerColor; // 花色
@property (nonatomic, copy) NSString *flowerName; // 花名
@end
可以通过打印对象地址看出,通过将已创建的对象存到享元池中的方式能重复利用之前已创建的对象,有效减少了内存的开销。
FlowerFactory *factory = [[FlowerFactory alloc] init];
NSMutableArray *arrayFlowers = [[NSMutableArray alloc] init];
// for循环调用
for (int i = 0; i < 5; ++i) {
FlowerType flowerType = arc4random_uniform(kTotalNumberFlower);
// 使用缓存池工厂方法来调用.类型是随机的
Flower *flower = [factory flowerViewWithType:flowerType];
// 简单的创建方式
// Flower *flower = [[Flower alloc] init];
[arrayFlowers addObject:flower];
// 打印详情
[factory detailsType];
}
打印结果:
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016d0280>, key = 1
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016810c0>, key = 0
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016d0280>, key = 1
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016810c0>, key = 0
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016d0280>, key = 1
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016810c0>, key = 0
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016d0280>, key = 1
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016810c0>, key = 0
FlyWeightDemo[67621:13837313] di zhi = <Flower: 0x6000016d0280>, key = 1
总结
享元模式,换句话说就是共享对象,在某些对象需要重复创建,且最终只需要得到单一结果的情况下使用。因为此种模式是利用先前创建的已有对象,通过某种规则去判断当前所需对象是否可以利用原有对象做相应修改后得到想要的效果,如以上实例,随机创建的花,最后相同类型的花只需要创建一次便可。此种模式下,同一类型的花,其地址都是同一个,所以说此模式适用于结果注重单一结果的情况。
主要解决
在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
何时使用
1、系统中有大量对象。
2、这些对象消耗大量内存。
3、这些对象的状态大部分可以外部化。
4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
5、系统不依赖于这些对象身份,这些对象是不可分辨的。
如何解决
用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。
应用实例
如IOS 中的 UITableViewCell、UICollectionViewCell。
优缺点
优点:大大减少对象的创建,降低系统的内存,使效率提高。
缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
使用场景
1、系统有大量相似对象。
2、需要缓冲池的场景。
最后文中代码Demo:享元模式