享元模式

简介

Use sharing to support large numbers of fine-grained objects efficiently.

使用共享对象可有效地支持大量的细粒度的对象。

享元模式(Flyweight)又称为轻量级模式,它是一种对象结构型模式。

面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。享元模式正是为解决这一类问题而诞生的。

享元模式是对象池的一种实现。类似于线程池,线程池可以避免不停的创建和销毁多个对象,消耗性能。享元模式也是为了减少内存的使用,避免出现大量重复的创建销毁对象的场景。

享元模式的宗旨是共享细粒度对象,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。

享元模式把一个对象的状态分成内部状态和外部状态,内部状态即是不变的,外部状态是变化的;然后通过共享不变的部分,达到减少对象数量并节约内存的目的。

享元模式本质:缓存共享对象,降低内存消耗

主要解决

当系统中多处需要同一组信息时,可以把这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多处需要使用的地方,避免大量同一对象的多次创建,消耗大量内存空间。

享元模式其实就是工厂模式的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法生成对象的,只不过享元模式中为工厂方法增加了缓存这一功能。

优缺点

优点

享元模式可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份,降低内存占用,增强程序的性能;

享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享;

缺点

享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;

为了使对象可以共享,享元模式需要将享元对象的状态外部化,而且外部状态必须具备固化特性,不应该随内部状态改变而改变,否则会导致系统的逻辑混乱;

使用场景

系统中存在大量的相似对象;

细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;

需要缓冲池的场景;

模式讲解

首先来看下享元模式的通用 UML 类图:

image

享元模式

从 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、结构图

image.png

享元模式

二、示例

​ 享元类的设计是享元模式的要点之一,在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入的方式添加到享元类中。享元工厂类是设计的核心。

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对象,这样就大大减少了对象的创建,实现了大量内存占用,导致内存泄露的问题

image

享元模式.png

二.为什么要使用享元模式?

一个完美的应用,不仅仅是界面和功能上的完美,如果一个应用拥有出众的界面,强大的功能,但是用户一使用
就卡的不行,或者说有延迟,这样用户会是什么感觉,当然苹果也许不是很明显,即使你的应用再烂,真正在真机上跑的时候也不会出现类似android卡顿的那样,但是你要是细心了,还是会有点发现的,作为开发者我们,应该去解决这样的问题,是我们代码的问题,我们就要去解决

三.怎么使用享元模式?

下面我直接使用UITabelView举例:

1.重新cell创建方法:


image.png

元对象.png
2.具体实现:


image.png
实现.png
从代码中,我们可以看出我需要显示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

iOS设计模式——享元模式

标签:

原文地址: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);
}
image.png

参考链接: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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343