iOS设计模式之享元模式

57 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情


设计模式相信大家都很熟悉了,但是越是基础的东西也越是需要经常的回顾与思考,于是着手写一个温故而知新的设计模式回顾系列。
在 8 月,准备把各个常用的不常用的设计模式都进行一次回顾,并大概聊一下各个模式的特点与在 iOS 中的大概使用场景与情况。

这里是设计模式回顾的第二篇,享元模式的相关回顾。

享元模式

1、认识享元模式

首先让我们先看下关于享元模式的定义(来自于《设计模式》(Addison-Wesley,1994))

它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件

享元模式从定义上看是有点类似于单例模式的,甚至从夸张一点,从广义上来说,单例模式属于特殊的享元模式,即只有一个对象的享元。而享元模式则属于拥有多种状态的单例模式,且不同状态有不同的对象,每个对象都可以共享。

在 iOS 中,UITableViewCell 的复用可以看成是一个非典型的享元模式,只不过将享元的范围从整个应用修改为了单个 tableView,我们可以观察到,相同的 identifier 是对应的 cell 地址是相同的。

2、什么场景使用享元模式

  • 存在大量相同对象或者只有一些外部状态不同的对象时,而这些对象造成了很大的存储开销的时候
  • 存在多种单例,单例与单例之间仅存在外部状态不同的情况

享元状态使用频率不高,因为大多数的情况下不会碰到同时存在的大量对象,除非是为了一些动画特效等。有时一些轻实例的方案也可以使用享元模式来实现。

3、享元模式的使用

  1. 在享元对象中定义所有的外部状态枚举和用来存放的字典
  2. 将整个享元对象单例化
  3. 通过状态不同,获取不同的对象

4、总结

享元模式的作用是为了减少内存或者管理相同类的不同状态,相对其他的设计模式而言,所存在的使用场景较少,在对象少的情况下,额外处理反而可能会有过度设计的风险。

5、demo

Flyweight.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, FlyweightType) {
    FlyweightType1,
    FlyweightType2,
    FlyweightType3,
};

@interface Flyweight : NSObject

/**
 获取共享对象

 @param status 状态
 */
- (id)singleFromStatus:(FlyweightType)status;

/**
 单例
 */
+ (Flyweight *)shareFlyweight;
@end

Flyweight.m

#import "Flyweight.h"

@interface Flyweight ()
@property (nonatomic, strong) NSMutableDictionary *dict;
@end

@implementation Flyweight

- (id)singleFromStatus:(FlyweightType)status {
    id result;
    if (!self.dict) {
        self.dict = [NSMutableDictionary dictionary];
    }
    if (self.dict[@(status)]) {
        result = self.dict[@(status)];
    }
    else {
        UILabel *label = [UILabel new];
        label.text = [NSString stringWithFormat:@"%ld",status];
        self.dict[@(status)] = label;
        result = label;
    }
    return result;
}

#pragma mark- public method
+ (Flyweight *)shareFlyweight {
    static Flyweight *single = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        single = [[super allocWithZone:NULL] init];
    });
    return single;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [Flyweight shareFlyweight];
}

+ (id)copyWithZone:(struct _NSZone *)zone {
    return [Flyweight shareFlyweight];
}

+ (id)mutableCopyWithZone:(struct _NSZone *)zone {
    return [Flyweight shareFlyweight];
}

- (id)copyWithZone:(NSZone *)zone{
    return  [Flyweight shareFlyweight];
}

- (id)mutableCopyWithZone:(NSZone *)zone{
    return [Flyweight shareFlyweight];
}
@end