Objective-C编程之道 iOS设计模式解析
iOS设计模式解析-工厂模式
iOS设计模式解析-抽象工厂模式
iOS设计模式解析-外观模式
iOS设计模式解析-中介者模式
iOS设计模式解析-观察者模式
iOS设计模式解析-装饰模式
iOS设计模式解析-责任链模式
iOS设计模式解析-模板方法
iOS设计模式解析-策略模式
iOS设计模式解析-享元模式
iOS设计模式解析-代码地址
何为享元模式
实现享元模式需要两个关键组件,通常是可共享的享元对象和保存它们的池。某种中央对象维护这个池,并从它返回适当的实例。
享元模式:运用共享技术有效地支持大量细粒度的对象。
何时使用享元模式
在以下情形,自然会考虑使用这一模式。
- 应用程序使用很多对象;
- 在内存中保存对象会影响内幕内存性能;
- 对象的多数持有状态(外在状态)可以放到外部而轻量化;
- 移除了外在状态之后,可以用较少的共享对象替代原来的那组对象;
- 应用程序不依赖于对象标识,因为共享对象不能提供唯一的标识。
下面使用可共享的花朵池绘制几百个(甚至更多)花朵图案,以说明这一模式的概念。
FlowerView
#import
#import
@interface FlowerView : UIImageView
- (void) drawRect:(CGRect)rect;
@end
#import "FlowerView.h"
@implementation FlowerView
- (void) drawRect:(CGRect)rect
{
[self.image drawInRect:rect];
}
@end
再简单不过了!它只重载了UIImageView的drawRect:rect方法仅此而已。
FlowerFactory
#import
#import
typedef enum
{
kAnemone,
kCosmos,
kGerberas,
kHollyhock,
kJasmine,
kZinnia,
kTotalNumberOfFlowerTypes
} FlowerType;
@interface FlowerFactory : NSObject
{
NSMutableDictionary *flowerPool;
}
- (UIView *) flowerViewWithType:(FlowerType)type;
@end
FlowerFactory有一个NSMutableDictionary变量flowerPool,用来保存整个可供返回花朵的池。它也定义了根据FlowerType参数返回特定UIView实例的工厂方法flowerViewWithType:(FlowerType)type; FlowerType是根据花的名称定义的一组枚举值,显然,kTotalNumberOfFlowerTypes是所支持花朵类型的总数。
#import "FlowerFactory.h"
#import "FlowerView.h"
@implementation FlowerFactory
- (UIView *) flowerViewWithType:(FlowerType)type
{
// lazy-load a flower pool
if (flowerPool == nil)
{
flowerPool = [[NSMutableDictionary alloc]
initWithCapacity:kTotalNumberOfFlowerTypes];
}
// try to retrieve a flower
// from the pool
UIView *flowerView = [flowerPool objectForKey:[NSNumber
numberWithInt:type]];
// if the type requested
// is not available then
// create a new one and
// add it to the pool
if (flowerView == nil)
{
UIImage *flowerImage;
switch (type)
{
case kAnemone:
flowerImage = [UIImage imageNamed:@"anemone.png"];
break;
case kCosmos:
flowerImage = [UIImage imageNamed:@"cosmos.png"];
break;
case kGerberas:
flowerImage = [UIImage imageNamed:@"gerberas.png"];
break;
case kHollyhock:
flowerImage = [UIImage imageNamed:@"hollyhock.png"];
break;
case kJasmine:
flowerImage = [UIImage imageNamed:@"jasmine.png"];
break;
case kZinnia:
flowerImage = [UIImage imageNamed:@"zinnia.png"];
break;
default:
break;
}
flowerView = [[FlowerView alloc]
initWithImage:flowerImage];
[flowerPool setObject:flowerView
forKey:[NSNumber numberWithInt:type]];
}
return flowerView;
}
@end
花朵池flowerPool没有在FlowerFactory的init方法中初始化,而是在工厂方法flowerViewWithType:中进行懒加载。池的默认容量是kTotalNumberOfFlowerTypes(也就是6)。如果请求的实例不在池中,工厂就会用适当的花朵图像创建一个新的flowerView的实例,并以type作为键,以新的实例作为值,加到池中。对于已创建的花朵,随后的请求将返回池中的实例,从池中共享花朵的机制相当简单。
客户端调用
- (void)viewDidLoad
{
[super viewDidLoad];
// construct a flower list
FlowerFactory *factory = [[FlowerFactory alloc] init];
NSMutableArray *flowerList = [[NSMutableArray alloc]
initWithCapacity:500];
for (int i = 0; i < 500 ; ++i)
{
// retrieve a shared instance
// of a flower flyweight object
// from a flower factory with a
// random flower type
FlowerType flowerType = arc4random() % kTotalNumberOfFlowerTypes;
UIView *flowerView = [factory flowerViewWithType:flowerType];
// UIView *flowerView = [[FlowerView alloc]
// initWithImage:[UIImage imageNamed:@"zinnia.png"]];
// set up a location and an area for the flower
// to display onscreen
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGFloat x = (arc4random() % (NSInteger)screenBounds.size.width);
CGFloat y = (arc4random() % (NSInteger)screenBounds.size.height);
NSInteger minSize = 10;
NSInteger maxSize = 50;
CGFloat size = (arc4random() % (maxSize - minSize + 1)) + minSize;
// assign attributes for a flower
// to an extrinsic state object
ExtrinsicFlowerState *extrinsicState = [[ExtrinsicFlowerState alloc]init];
extrinsicState.flowerView = flowerView;
extrinsicState.area = CGRectMake(x, y, size, size);
// add an extrinsic flower state
// to the flower list
[flowerList addObject:extrinsicState];
}
// add the flower list to
// this FlyweightView instance
//xib中记得设置view为FlyweightView
[(FlyweightView *)self.view setFlowerList:flowerList];
}
节省内存的事情请看下面两种方法,然后做出比较(500数字可适当改大)
UIView *flowerView = [factory flowerViewWithType:flowerType];
UIView *flowerView = [[FlowerView alloc]
initWithImage:[UIImage imageNamed:@"zinnia.png"]];
总结:我们设计了一个可以在屏幕上显示500朵花的程序,而只用了6个不同花朵图案的实例,这些不同的花朵实例,把一些与众不同的可被标识的信息(即位置和大小)去掉,只剩下显示花朵图案的基本操作。在请求特定的花朵的时候,客户端需要向花朵实例提供某些与众不同的信息(外在状态),让它使用这些信息绘制一朵与众不同的花。读到这里你是否想起了cell的重用池呢?本节的例子很简单,demo链接在上面。