简介
Use sharing to support large numbers of fine-grained objects efficiently.
使用共享对象可有效地支持大量的细粒度的对象。
享元模式(Flyweight)又称为轻量级模式,它是一种对象结构型模式。
面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。享元模式正是为解决这一类问题而诞生的。
享元模式是对象池的一种实现。类似于线程池,线程池可以避免不停的创建和销毁多个对象,消耗性能。享元模式也是为了减少内存的使用,避免出现大量重复的创建销毁对象的场景。
享元模式的宗旨是共享细粒度对象,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。
享元模式把一个对象的状态分成内部状态和外部状态,内部状态即是不变的,外部状态是变化的;然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
享元模式本质:缓存共享对象,降低内存消耗
主要解决
当系统中多处需要同一组信息时,可以把这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多处需要使用的地方,避免大量同一对象的多次创建,消耗大量内存空间。
享元模式其实就是工厂模式的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法生成对象的,只不过享元模式中为工厂方法增加了缓存这一功能。
优缺点
优点
享元模式可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份,降低内存占用,增强程序的性能;
享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享;
缺点
享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
为了使对象可以共享,享元模式需要将享元对象的状态外部化,而且外部状态必须具备固化特性,不应该随内部状态改变而改变,否则会导致系统的逻辑混乱;
使用场景
系统中存在大量的相似对象;
细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;
需要缓冲池的场景;
模式讲解
首先来看下享元模式的通用 UML 类图:
享元模式
从 UML 类图中,我们可以看到,享元模式主要包含三种角色:
抽象享元角色(Flyweight):享元对象抽象基类或者接口,同时定义出对象的外部状态和内部状态的接口或实现;
具体享元角色(ConcreteFlyweight):实现抽象角色定义的业务。该角色的内部状态处理应该与环境无关,不能出现会有一个操作改变内部状态,同时修改了外部状态;
享元工厂(FlyweightFactory):负责管理享元对象池和创建享元对象;
参考链接:https://www.jianshu.com/p/a2aa75939766 来源:简书
iOS 设计模式之享元模式
一、概念
1、享元模式的动机
现代社会都讲究资源节约,资源复用。在软件系统中,有时候也会存在资源浪费的情况,例如在计算机内存中存储了多个完全相同或者非常相似的对象,如果这些对象的数量太多将导致系统运行代价过高,而享元模式可以节约内存使用空间,实现对这些相同或者相似对象的共享访问。
2、享元模式的定义
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
3、享元对象的2个状态
1)内部状态(Intrinsic State):内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享。
2)外部状态(Extrinsic State):外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态通常由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。
正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。
4、享元模式的4个角色
1)Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
2)ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。
3)UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
4)FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计。
在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
5、结构图
享元模式
二、示例
享元类的设计是享元模式的要点之一,在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入的方式添加到享元类中。享元工厂类是设计的核心。
1)先创建一个Cell类,里面有内部状态和设置外部状态的方法,表示抽象享元类;
2)再创建ImageCell和TextCell两个类,都继承自Cell类,表示具体享元类;
3)最后创建一个CellFactory类,里面有一个享元池,表示享元工厂类。
Cell类:
@interface Cell : NSObject
@property(nonatomic, copy, readonly) NSString *cellID; //内部状态
- (void)setRowIndex:(NSInteger)rowIndex; //外部状态
@end
@implementation Cell
- (NSString *)cellID {
return @"cellID";
}
- (void)setRowIndex:(NSInteger)rowIndex {
NSLog(@"Cell复用ID = %@, rowIndex = %ld", self.cellID, rowIndex);
}
@end
ImageCell和TextCell类:
// ImageCell
@interface ImageCell : Cell
@end
@implementation ImageCell
- (NSString *)cellID {
return @"ImageCell";
}
@end
// TextCell
@interface TextCell : Cell
@end
@implementation TextCell
- (NSString *)cellID {
return @"TextCell";
}
@end
CellFactory类:
// .h文件
@interface CellFactory : NSObject
+ (instancetype)sharedInstance;
- (Cell *)getCellWithCellID:(NSString *)cellID;
@end
// .m文件
@interface CellFactory ()
@property(nonatomic, strong) NSMutableDictionary *dict; //享元池
@end
@implementation CellFactory
- (instancetype)init
{
self = [super init];
if (self) {
_dict = [NSMutableDictionary dictionary];
}
return self;
}
+ (instancetype)sharedInstance { //单例模式
static CellFactory *factory;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
factory = [CellFactory new];
});
return factory;
}
- (Cell *)getCellWithCellID:(NSString *)cellID { //享元工厂类核心代码
if ([self.dict.allKeys containsObject:cellID]) {
return [self.dict objectForKey:cellID];
} else {
if ([cellID isEqualToString:@"ImageCell"]) {
ImageCell *imageCell = [ImageCell new];
[self.dict setObject:imageCell forKey:cellID];
return imageCell;
} else if ([cellID isEqualToString:@"TextCell"]) {
TextCell *textCell = [TextCell new];
[self.dict setObject:textCell forKey:cellID];
return textCell;
} else {
return nil;
}
}
}
@end
运行代码:
- (void)viewDidLoad {
[super viewDidLoad];
/**
说明:UITableViewCell的复用机制与这里Demo不尽相同,需要查看UITableViewCell的复用机制请自行查阅资料
这里的Demo就是展示享元模式设计的大概思路
*/
CellFactory *factory = [CellFactory sharedInstance];
Cell *imageCell1, *imageCell2, *imageCell3, *textCell1, *textCell2;
imageCell1 = [factory getCellWithCellID:@"ImageCell"];
imageCell2 = [factory getCellWithCellID:@"ImageCell"];
imageCell3 = [factory getCellWithCellID:@"ImageCell"];
NSLog(@"imageCell1 = %p", imageCell1);
NSLog(@"imageCell2 = %p", imageCell2);
NSLog(@"imageCell3 = %p", imageCell3);
NSLog(@"-------------------");
textCell1 = [factory getCellWithCellID:@"TextCell"];
textCell2 = [factory getCellWithCellID:@"TextCell"];
NSLog(@"textCell1 = %p", textCell1);
NSLog(@"textCell2 = %p", textCell2);
NSLog(@"-------------------");
// 设置外部状态
[imageCell1 setRowIndex:0];
[imageCell2 setRowIndex:1];
[textCell1 setRowIndex:2];
}
打印结果:从享元工厂类得到的对象内存地址一样,很好地复用了对象。
imageCell1 = 0x600002dbcc70
imageCell2 = 0x600002dbcc70
imageCell3 = 0x600002dbcc70
-------------------
textCell1 = 0x600002dac660
textCell2 = 0x600002dac660
-------------------
Cell复用ID = ImageCell, rowIndex = 0
Cell复用ID = ImageCell, rowIndex = 1
Cell复用ID = TextCell, rowIndex = 2
三、总结
当系统中存在大量相同或者相似的对象时,享元模式是一种较好的解决方案,它通过共享技术实现相同或相似的细粒度对象的复用,从而达到了“节约内存,提高性能”的效果。
1、优点
1、可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。
2、享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
2、缺点
1、享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
2、为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
3、适用场景
1、一个系统有大量相同或者相似的对象,造成内存的大量耗费。
2、对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
3、在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,应当在需要多次重复使用享元对象时才值得使用享元模式。
4、iOS应用举例
例如在屏幕上显示500朵不同类型的花,假设这些花的类型只有5种,如果不使用享元模式那么就要创建500个UIImageView对象,耗费大量内存资源。如果使用享元模式,只需要创建5种UIImageView对象放进享元池,外部状态就是500朵花在屏幕中不同的位置,然后通过drawRect绘制最终的显示效果。
Demo地址:iOS-Design-Patterns
参考链接:https://www.jianshu.com/p/0dd498f13d09 来源:简书
享元模式
1、什么是享元模式
它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接
受的大量内存的大量物件
在我看来,算是一个类中有多种的单例,单例模式属于特殊的享元模式,即只有一个对象的享元。享元属于拥有多种状态的单例模式,不同状态有不同的对象,每个对象都可以共享。
2、享元模式用在什么地方
存在大量相同对象或者只有一些外部状态不同的对象时,而这些对象造成了很大的存储开销的时候
存在多种单例,单例与单例之间仅存在外部状态不同的情况
享元状态使用频率不高,因为大多数的情况下不会碰到同时存在的大量对象,除非是为了一些动画特效等。
3、享元模式的使用
在享元对象中定义所有的外部状态枚举和用来存放的字典
将整个享元对象单例化
通过状态不同,获取不同的对象
4、总结
享元模式的作用是为了减少内存,不过在一般的情况下,是用不到的,在对象少的情况下,不需要额外处理。
至少我在当前的工程中还没遇到过使用的情况。
5、demo
//Flyweight.h
#import "Flyweight.h"
typedef NS_ENUM(NSUInteger, FlyweightType) {
FlyweightType1,
FlyweightType2,
FlyweightType3,
};
//Flyweight.m
@interface Flyweight : NSObject
/**
获取共享对象
@param status 状态
*/
- (id)singleFromStatus:(FlyweightType)status;
/**
单例
*/
+ (Flyweight *)shareFlyweight;
@end
#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
参考链接:https://www.it610.com/article/1249504234588721152.htm
iOS 享元模式
一.什么是享元模式?
享元模式主要用于减少同一类对象的大量创建,以减少内存占用,提高项目流畅度,在iOS开发中,大家肯定都用过UITableViewCell,UICollectionViewCell,这两个类在使用过程中就使用了享元模式,工作原理基本就是:利用重用池重用思想,创建页面可显示的cell个数的对象,在页面滚动过程中监听每个cell的状态,从页面消失的cell被放回重用池,将要显示的cell先去重用池中去取,如果可以取到,则继续使用这个cell,如果没有多余的cell,就重新创建新的,这样即使你有100条数据,也仅仅只会创建页面可显示个数的cell对象,这样就大大减少了对象的创建,实现了大量内存占用,导致内存泄露的问题
享元模式.png
二.为什么要使用享元模式?
一个完美的应用,不仅仅是界面和功能上的完美,如果一个应用拥有出众的界面,强大的功能,但是用户一使用
就卡的不行,或者说有延迟,这样用户会是什么感觉,当然苹果也许不是很明显,即使你的应用再烂,真正在真机上跑的时候也不会出现类似android卡顿的那样,但是你要是细心了,还是会有点发现的,作为开发者我们,应该去解决这样的问题,是我们代码的问题,我们就要去解决
三.怎么使用享元模式?
下面我直接使用UITabelView举例:
1.重新cell创建方法:
元对象.png
2.具体实现:
从代码中,我们可以看出我需要显示100个cell,但是实际只创建了8个cell,内存占用上相比100个cell对象的内存缩减到了原来的十分之一,流畅度可想而知
菜鸟教程: http://www.runoob.com/design-pattern/flyweight-pattern.html
百度百科: https://baike.baidu.com/item/享元模式/10541959?fr=aladdin
其他设计模式
工厂模式:http://www.jianshu.com/p/6f3ffb1397f7
责任链模式:http://www.jianshu.com/p/30475126694a
观察者模式:http://www.jianshu.com/p/a6a6e5a8e8bd
参考链接:https://www.jianshu.com/p/f9c53b9825e4
iOS设计模式——享元模式
公共交通(如公共汽车)已有一百多年的历史了。大量去往相同方向的乘客可以分担保有和经营车辆(如公共汽车)的费用。公共汽车有多个站台,乘客沿着路线在接近他们目的地的地方上下车。到达目的地的费用仅与行程有关。跟保有车辆相比,乘坐公共汽车要便宜得多。这就是利用公共资源的好处。
在面向对象软件设计中,我们利用公共对象不仅能节省资源还能提高性能。比方说,某个人物需要一个类的一百万个实例,但我们可以把这个类的一个实例让大家共享,而把某些独特的信息放在外部,节省的资源可能相当可观(一个实例与一百万个实例的差别)。共享的对象只提供某些内在的信息,而不能用来识别对象。专门用于设计可共享对象的一种设计模式叫做享元模式。
何为享元模式?
实现享元模式需要两个关键组件,通常是可共享的享元对象和保存它们的池。某种中央对象为何这个池,并从它返回适当的实例。工厂是这一角色的理想候选。它可以通过一个工厂方法,根据父类型返回各种类型的具体享元对象,其主要的目的就是为何池中的享元对象,并适当地从中返回享元对象。
使得享元对象是轻量级的最重要原因是什么呢?不是它们的大小,而是通过共享能够节省的空间总量。某些对象的独特状态可以拿到外部,在别处管理,其余部分被共享。比如说,原来需要一个类的一百万个对象,但因为这个类的对象为享元,现在只要一个就够了。这就是由于可共享的享元对象让整个系统变得轻量的原因。通过仔细的设计,内存的节省非常可观。在iOS开发中,节省内存意味着提升整体性能。
享元模式:运用共享技术有效地支持大量细粒度的对象。
何时使用享元模式?
@:应用程序使用很多对象。
@:在内存中保存对象会影响内存性能。
@:对象的多数特有状态可以放到外部而轻量化。
@:移除了外在状态后,可以用较少的共享对象替代原来的那组对象。
@:应用程序不依赖于对象标识,因为共享对象不能提供唯一的标识。
享元模式的实例应用
我们创建一个WebSiteFactory工厂类,来维护池中的享元对象,根据父类型返回各种类型的具体享元对象,代码如下:
#import <Foundation/Foundation.h>
#import "WebSiteProtocol.h"
@interface WebSiteFactory : NSObject
@property (nonatomic, strong) NSDictionary *flyweights; //共享对象
- (id<WebSiteProtocol>)getWebSiteCategory:(NSString *)webKey;
- (NSInteger)getWebSiteCount;
@end
#import "WebSiteFactory.h"
#import "ConcreteWebSite.h"
@implementation WebSiteFactory
- (instancetype)init {
self = [super init];
if (self) {
_flyweights = [NSDictionary dictionary];
}
return self;
}
- (id<WebSiteProtocol>)getWebSiteCategory:(NSString *)webKey {
__block id<WebSiteProtocol> webset = nil;
[self.flyweights enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (webKey == key) {
webset = obj;
*stop = YES;
}
}];
if (webset == nil) {
ConcreteWebSite *concreteWebset = [[ConcreteWebSite alloc] init];
concreteWebset.webName = webKey;
webset = concreteWebset;
NSMutableDictionary *mutabledic = [NSMutableDictionary dictionaryWithDictionary:self.flyweights];
[mutabledic setObject:webset forKey:webKey];
self.flyweights = [NSDictionary dictionaryWithDictionary:mutabledic];
}
return webset;
}
- (NSInteger)getWebSiteCount {
return self.flyweights.count;
}
@end
代码中的getWebSiteCategory方法可以返回具体的享元对象,返回的这个享元对象同时遵守WebSiteProtocol的协议,WebSiteProtocol的代码如下:
#import <Foundation/Foundation.h>
#import "User.h"
@protocol WebSiteProtocol <NSObject>
- (void)use:(User *)user;
@end
ConcreteWebSite的代码如下:
#import <Foundation/Foundation.h>
#import "WebSiteProtocol.h"
@interface ConcreteWebSite : NSObject <WebSiteProtocol>
@property (nonatomic, copy) NSString *webName;
@end
#import "ConcreteWebSite.h"
@implementation ConcreteWebSite
- (void)use:(User *)user {
NSLog(@"网站分类:%@ 用户名字:%@", self.webName, user.userName);
}
@end
User的代码如下:
#import <Foundation/Foundation.h>
@interface User : NSObject
@property (nonatomic, copy) NSString *userName;
@end
#import "User.h"
@implementation User
@end
至此,享元模式的代码已经完成了,我们来看下在客户端怎么使用享元模式,代码如下:
#import "ViewController.h"
#import "WebSiteProtocol.h"
#import "WebSiteFactory.h"
#import "ConcreteWebSite.h"
#import "User.h"
typedef id<WebSiteProtocol> WebsiteType;
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 通过工厂方法返回各种具体享元对象,维护池中的享元对象
WebSiteFactory *factory = [[WebSiteFactory alloc] init];
// 返回具体的享元对象
WebsiteType type1 = [factory getWebSiteCategory:@"首页"];
User *user1 = [[User alloc] init];
user1.userName = @"张三";
// 享元对象都具有use方法
[type1 use:user1];
WebsiteType type2 = [factory getWebSiteCategory:@"商店"];
User *user2 = [[User alloc] init];
user2.userName = @"李四";
[type2 use:user2];
WebsiteType type3 = [factory getWebSiteCategory:@"案例"];
User *user3 = [[User alloc] init];
user3.userName = @"王五";
[type3 use:user3];
NSInteger count = [factory getWebSiteCount];
NSLog(@"个数: %ld", (long)count);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
输出如下:
2015-09-12 15:59:55.322 FlyweightPattern[42020:1723017] 网站分类:首页 用户名字:张三
2015-09-12 15:59:55.322 FlyweightPattern[42020:1723017] 网站分类:商店 用户名字:李四
2015-09-12 15:59:55.322 FlyweightPattern[42020:1723017] 网站分类:案例 用户名字:王五
2015-09-12 15:59:55.323 FlyweightPattern[42020:1723017] 个数: 3
分享相同的资源以执行任务,可能比使用个人的资源完成同样的事情更加高效。享元模式可以通过共享一部分必需的对象,来节省大量的内存。
Demo链接地址:https://github.com/guoshimeihua/FlyweightPattern.git
标签:
原文地址:http://my.oschina.net/daguoshi/blog/505322
iOS架构师_享元模式
享元模式定义:相同的数据就拿来共享
1、可共享享元对象
2、享元池
减少同一类对象的大量创建,减少节约了内存空间。
使用范围:服务器端:查询火车票(共享对象)
iOS端:多线程(线程池),UITableViewCell,UICollectionViewCell
UML结构图
代码示例
创建工厂FlowerFactory类,并且创建类Flower
Flower.h
#import <Foundation/Foundation.h>
@interface Flower : NSObject
@property (nonatomic, copy) NSString *flowerColor; // 花色
@property (nonatomic, copy) NSString *flowerName; // 花名
@end
FlowerFactory.h
#import <Foundation/Foundation.h>
#import "Flower.h"
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
FlowerFactory.m
#import "FlowerFactory.h"
@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
ViewController.h调用
#import "ViewController.h"
#import "FlowerFactory.h"
#import "Flower.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化工厂
FlowerFactory *factory = [[FlowerFactory alloc] init];
NSMutableArray *arrayFlowers = [[NSMutableArray alloc] init];
// for循环调用
for (int i = 0; i < 5000*100; ++i) {
FlowerType flowerType = arc4random_uniform(kTotalNumberFlower);
// 使用缓存池工厂方法来调用.类型是随机的
Flower *flower = [factory flowerViewWithType:flowerType];
// 简单的创建方式
// Flower *flower = [[Flower alloc] init];
[arrayFlowers addObject:flower];
// 打印详情
[factory detailsType];
}
}
@end
此时我们查看内存
然后修改代码,使用常规方式创建对象
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 初始化工厂
FlowerFactory *factory = [[FlowerFactory alloc] init];
NSMutableArray *arrayFlowers = [[NSMutableArray alloc] init];
// for循环调用
for (int i = 0; i < 5000*100; ++i) {
FlowerType flowerType = arc4random_uniform(kTotalNumberFlower);
// 使用缓存池工厂方法来调用.类型是随机的
// Flower *flower = [factory flowerViewWithType:flowerType];
//使用常规方法创建
Flower * flower = [[Flower alloc]init];
[arrayFlowers addObject:flower];
// 打印详情
// [factory detailsType];
}
NSLog(@"flower== %lu",arrayFlowers.count);
}
参考链接:https://blog.csdn.net/wtdask/article/details/80540371
iOS设计模式之享元模式
享元模式
1、什么是享元模式
它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接
受的大量内存的大量物件
在我看来,算是一个类中有多种的单例,单例模式属于特殊的享元模式,即只有一个对象的享元。享元属于拥有多种状态的单例模式,不同状态有不同的对象,每个对象都可以共享。
2、享元模式用在什么地方
存在大量相同对象或者只有一些外部状态不同的对象时,而这些对象造成了很大的存储开销的时候
存在多种单例,单例与单例之间仅存在外部状态不同的情况
享元状态使用频率不高,因为大多数的情况下不会碰到同时存在的大量对象,除非是为了一些动画特效等。
3、享元模式的使用
在享元对象中定义所有的外部状态枚举和用来存放的字典
将整个享元对象单例化
通过状态不同,获取不同的对象
4、总结
享元模式的作用是为了减少内存,不过在一般的情况下,是用不到的,在对象少的情况下,不需要额外处理。
至少我在当前的工程中还没遇到过使用的情况。
5、demo
Flyweight.h
#import
#import
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