文档章节

iOS 设计模式 阅读笔记

云飞扬v5
 云飞扬v5
发布于 2016/08/14 10:15
字数 4906
阅读 22
收藏 0

第一章,你好,设计模式

图书相关的一些资源

http://www.ocdesignpatterns.com/

源代码下载地址 www.apress.com

设计模式是为特定场景下的问题而定制的解决方案。

 针对接口编程,而不是针对实现编程

接口定义了类型。类继承与借口继承的关系

类继承是通过复用父类的功能,来定义对象新的实现的一种机制。

使用接口的好处:

只要对象符合客户端所要求的接口,客户端就不必在意所使用对象的确切类型。

客户端只知道定义接口的协议或者抽象类,因此客户端对对象的类一无所知。

第3章 原型模式 Prototype

原型模式:使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象。

第4章 工厂模式

对调用的类来说,只需要知道事物的基类和工厂的实现类就可以,

返回的是抽象类。

 

抽象工厂
CanvasViewGenerator.h


#import "CanvasView.h"
@interface CanvasViewGenerator :NSObject

- (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame;

@end

CanvasViewGenerator.m

#import "CanvasViewGenerator.h"
@implement CanvasViewGenerator

- (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{
   return [[CanvasView alloc]initWithFrame:aFrame];

}



@end


抽象实体


实现工厂
PaperCanvasViewGenerator.h


#import "CanvasViewGenerator.h"
#import "PaperCanvasView.h"
@interface PaperCanvasViewGenerator :CanvasViewGenerator

- (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame;

@end

PaperCanvasViewGenerator.m

#import "PaperCanvasViewGenerator.h"
@implement PaperCanvasViewGenerator

- (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{
   return [[CanvasView alloc]initWithFrame:aFrame];

}


ClothCanvasViewGenerator.h

#import "ClothCanvasViewGenerator.h"
#import "ClothCanvasView.h"

@interface ClothCanvasViewGenerator :CanvasViewGenerator

- (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame;

@end

ClothCanvasViewGenerator.m

#import "ClothCanvasViewGenerator.h"
@implement ClothCanvasViewGenerator

- (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{
   return [[ClothCanvasView alloc]initWithFrame:aFrame];

}


实现实体

#import <UIKit/UIKit.h>
#import "CanvasView.h"
#import "PaperCanvasView.h"
@interface PaperCanvasView:CanvasView

    //私有变量

    //私有方法

- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        UIImage *backgroundImage = [UIImage imageNamed:@"paper"];
        UIImageView *backgroundView = [[UIImageView alloc]initWithImage:backgroundImage];
        [self addSubview:backgroundView];
    }
    return self;
}

@end

#import <UIKit/UIKit.h>
#import "CanvasView.h"
#import "ClothCanvasView.h"
@interface ClothCanvasView:CanvasView

    //私有变量

    //私有方法

- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        UIImage *backgroundImage = [UIImage imageNamed:@"cloth"];
        UIImageView *backgroundView = [[UIImageView alloc]initWithImage:backgroundImage];
        [self addSubview:backgroundView];
    }
    return self;
}

@end



//客户端调用工厂方法,客户端和具体的实现是解耦的,
//如果后续需要增加一种新的画布,客户端不需要修改已经有的代码,只需要在需要调用的地方添加即可

- (void)viewDidLoad{

   CanvasViewGenerator *defaultGenerator = [[ClothCanvasViewGenerator alloc]init];
   CanvasView *aCanvasView = [self loadCanvasViewWithGenerator:defaultGenerator];
   

}


- (void)loadCanvasViewWithGenerator:(CanvasViewGenerator *)generator{
     [canvasView_ removeFromSuperView];
     CGRect aFrame = CGRectMake(0,0,320,436);
     CanvasView *aCanvasView = [generator canvasViewWithFrame:aFrame];
     [self setCanvasView:aCanvasView];
     [self.view addSubview:aCanvasView];

}

第5章 抽象工厂

抽象工厂:提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类。

简单工厂,工厂方法,抽象工厂方法的区别

http://www.cnblogs.com/zhangchenliang/p/3700820.html

 

第6章 生成器

生成器:将一个复杂对象的构建和表现分离,相同的构建可以创建不同的表现。

 

第7章 单例

 

第三部分 接口适配

第8章 适配器

适配器模式:将一个类的接口转换为客户希望的另外一个接口,适配器模式使得由于接口不兼容而不能一起工作的那些类可以一起工作。

应用场景,

已有类接口与需求不匹配,

想要一个复用的类,该类能够与不兼容的其他类写作,

 

用块语法实现适配器

 

 

第9章 桥接

桥接模式:将抽象部分与实现部分分类,使他们都可以独立地变化

使用场景

抽象和实现都可以通过子类化独立进行扩展

对抽象的实现进行修改不应影响客户端代码

如果每个实现需要额外的子类以细化抽象,则说明有必要把他们分成2个部分

想在带有不同抽象接口的多个对象之间共享一个实现。

 

 

 

 

第10章 外观

外观:为系统中的一组接口提供一个统一的接口,外观定义了一个高层接口,让子系统更易于使用。

 

汽车类,负责 启动,加油等操作

#import <Foundation/Foundation.h>


@interface Car : NSObject 
{

}

// ...

- (void) releaseBrakes;
- (void) changeGears;
- (void) pressAccelerator;
- (void) pressBrakes;
- (void) releaseAccelerator;

// ...

@end



#import "Car.h"


@implementation Car

- (void) releaseBrakes
{
	
}

- (void) changeGears
{
	
}

- (void) pressAccelerator
{
	
}

- (void) pressBrakes
{
	
}

- (void) releaseAccelerator
{
	
}

计价器,负责计算价格

#import <Foundation/Foundation.h>


@interface Taximeter : NSObject 
{

}

- (void) start;
- (void) stop;

@end

#import "Taximeter.h"


@implementation Taximeter

- (void) start
{
	
}

- (void) stop
{
	
}

@end

 

 

司机类,负责开车和计价,但是给客户端调用的时候提供了唯一的方法 - (void) driveToLocation:(CGPoint) x;方便客户端调用

#import "Taximeter.h"


@implementation Taximeter

- (void) start
{
	
}

- (void) stop
{
	
}

@end


#import "CabDriver.h"


@implementation CabDriver

- (void) driveToLocation:(CGPoint) x
{
  // ...
  
  // set off the taximeter
  Taximeter *meter = [[Taximeter alloc] init];
  [meter start];
  
  // operate the vehicle
  // until location x is reached
  Car *car = [[Car alloc] init];
  [car releaseBrakes];
  [car changeGears];
  [car pressAccelerator];
  
  // ...
  
  // when it's reached location x
  // then stop the car and taximeter
  [car releaseAccelerator];
  [car pressBrakes];
  [meter stop];
  
  // ...
}

@end

调用代码

 CabDriver *cab = [[CabDriver alloc]init];

  [cab driveToLocation:CGPointMake(100, 100)];

 

    

 

 

第11章 中介者

中介者模式,用一个对象来封装一系列对象的交互方式。中介者使各对象不需要互相饮用,从而使其耦合松散,而且可以独立地改变他们之间的交互。

使用场景:对象之间的交互虽然定义明确然而非常复杂,导致一组对象彼此互相依赖

因为对象引用了许多其他对象并与其通讯,导致对象难以复用

想要定制一个分部在多个类的逻辑或行为,又不想生成太多子类

第12章 观察者

观察者模式:定义对象见的一种一对多的依赖关系,当一个对象的状态发生改变时,依赖于他的对象都得到通知并被自动更新。

使用场景:

有2种抽象类型互相依赖,将它们封装在各自的对象中,就可以对它们单独进行改变和复用

对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变

一个对象必须通知其他对象,而它又不知道其他对象是什么。

通知 和键值观察实现了观察者模式

第13章 组合模式

组合模式:将对象组合成树状结构以标示 部分-整体的层次结构,组合使得用户对单个对象和组合对象的使用具有一致性。

使用场景:

想获得对象抽象的树形表示

想让客户端统一处理组合结构中的所有对象

Cocoa Touch中的UIView 就是一个层次结构的例子。

第14章 迭代器

迭代器:提供一种方法顺序访问一个聚合对象中的各元素,而又不需暴露该对象的内部表示。

使用场景:需要访问组合对象的内容,而又不需暴露其内部表示

需要通过多种方式遍历组合对象

需要提供一个统一的接口,用来便利各种类型的组合对象。

NSEnumerator实现了迭代器模式。能够顺序遍历各种集合

快速枚举 forin,使用了指针运算

NSArray有个方法(void)makeObjectsPerformSelector:(SEL)aSelector;

第15章 访问者

访问者模式:表示一个作用于某对象结构中的各元素的操作,它让我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

应用场景:一个复杂的对象结构包含很多其它对象,它们有不同的接口(比如组合体),这些对象实施一些依赖于其它类型的操作。

需要对一个组合结构中的对象进行很多不相关的操作,但是不想让这些操作污染这些对象的类。可以将相关的操作集中起来,定义在一个访问者类中,并在需要在访问者中定义的操作时使用它。

定义复杂结构的类很少作修改,但经常需要向其添加新的操作。

 

 

第16章 装饰

装饰模式:动态地给一个对象添加一些额外的职责,就扩展功能来说,装饰模式相比生成子类更为灵活。

想要在不影响其它对象的情况下,以动态,透明的方式给耽搁对象添加职责。

想要扩展一个类的行为,却做不到。类定义可能被隐藏,无法进行子类化,或者,对类的每个行为的扩展,为支持每种功能的组合将产生大量的子类。

对类的职责的扩展是可选的。

可以通过 forwardingTargetForSelector:(SEL)aSelector 的方法或者

可以通过范畴实现装饰模式

 

定义基类的变化扩展类

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UIImage (BaseFilter)

- (CGContextRef) beginContext;
- (UIImage *) getImageFromCurrentImageContext;
- (void) endContext;

@end



#import "UIImage+BaseFilter.h"


@implementation UIImage (BaseFilter)

- (CGContextRef) beginContext
{
  // Create a graphics context with the target size
  // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions 
  // to take the scale into consideration
  // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
  CGSize size = [self size];
  if (NULL != UIGraphicsBeginImageContextWithOptions)
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
  else
    UIGraphicsBeginImageContext(size);
  
  CGContextRef context = UIGraphicsGetCurrentContext();
  
  return context;
}

- (UIImage *) getImageFromCurrentImageContext
{
  [self drawAtPoint:CGPointZero];
  
  // Retrieve the UIImage from the current context
  UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext();
  
  return imageOut;
}

- (void) endContext
{
  UIGraphicsEndImageContext();
}

更加具体的一个扩展

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UIImage (Transform)

- (UIImage *) imageWithTransform:(CGAffineTransform)transform;

@end


#import "UIImage+Transform.h"
#import "UIImage+BaseFilter.h"

@implementation UIImage (Transform)

- (UIImage *) imageWithTransform:(CGAffineTransform)transform
{
  CGContextRef context = [self beginContext];
  
  // setup transformation
  CGContextConcatCTM(context, transform);
  
  // Draw the original image to the context
  UIImage *imageOut = [self getImageFromCurrentImageContext];
  
  [self endContext];
  
  return imageOut;
}

@end

 

第17章 责任链

责任链模式:使多个对象都有机会请求处理请求,从而避免请求的发送者何接收者之间发生耦合。此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

使用场景:有多个对象可以处理请求,而处理程序直邮在运行时才能确定。

向一组对象发出请求,而不想显式指定处理请求的特定处理程序。

一个攻击游戏人物护甲的演示

攻击基类(什么也没有。。。)

#import <Foundation/Foundation.h>


@interface Attack : NSObject 
{

}

@end

#import "Attack.h"


@implementation Attack

@end

护甲基类,有一个下一个处理者的属性,基类中定义了处理攻击的行为,会调用下一个处理者的该方法

#import <Foundation/Foundation.h>
#import "Attack.h"

@interface AttackHandler : NSObject 
{
  @private
  AttackHandler *nextAttackHandler_;
}

@property (nonatomic, retain) AttackHandler *nextAttackHandler;

- (void) handleAttack:(Attack *)attack;

@end


#import "AttackHandler.h"


@implementation AttackHandler

@synthesize nextAttackHandler=nextAttackHandler_;


- (void) handleAttack:(Attack *)attack
{
  [nextAttackHandler_ handleAttack:attack];
}

@end

金属护甲可以识别处理SwordAttack,如果处理成功了,伤害不再继续传递

#import <Foundation/Foundation.h>
#import "AttackHandler.h"

@interface MetalArmor : AttackHandler
{

}

// overridden method
- (void) handleAttack:(Attack *)attack;

@end


#import "MetalArmor.h"
#import "SwordAttack.h"

@implementation MetalArmor

- (void) handleAttack:(Attack *)attack
{
  if ([attack isKindOfClass:[SwordAttack class]])
  {
    // no damage beyond this armor
    NSLog(@"%@", @"No damage from a sword attack!");
  }
  else 
  {
    NSLog(@"I don't know this attack: %@", [attack class]);
    [super handleAttack:attack];
  }
}

@end

水晶护甲可以识别处理MagicFireAttack,如果处理成功了,伤害不再继续传递,如果不能处理继续传递。

#import <Foundation/Foundation.h>
#import "AttackHandler.h"

@interface CrystalShield : AttackHandler
{

}

// overridden method
- (void) handleAttack:(Attack *)attack;

@end



#import "CrystalShield.h"
#import "MagicFireAttack.h"

@implementation CrystalShield

- (void) handleAttack:(Attack *)attack
{
  if ([attack isKindOfClass:[MagicFireAttack class]])
  {
    // no damage beyond this shield
    NSLog(@"%@", @"No damage from a magic fire attack!");
  }
  else 
  {
    NSLog(@"I don't know this attack: %@", [attack class]);
    [super handleAttack:attack];
  }
}

@end

 

游戏人物,接收所有的伤害

#import <Foundation/Foundation.h>
#import "AttackHandler.h"

@interface Avatar : AttackHandler
{

}

// overridden method
- (void) handleAttack:(Attack *)attack;

@end

#import "Avatar.h"


@implementation Avatar

- (void) handleAttack:(Attack *)attack
{
  // when an attack reaches this point,
  // I'm hit.
  // actual points taken off depends on
  // the type of attack.
  NSLog(@"Oh! I'm hit with a %@!", [attack class]);
}


@end

 

这个例子里面的伤害实现类都是基本没有内容的。。。

#import <Foundation/Foundation.h>
#import "Attack.h"

@interface SwordAttack : Attack
{

}

@end

#import "SwordAttack.h"


@implementation SwordAttack

@end



#import <Foundation/Foundation.h>
#import "Attack.h"

@interface MagicFireAttack : Attack
{

}

@end

#import "MagicFireAttack.h"


@implementation MagicFireAttack

@end





#import <Foundation/Foundation.h>
#import "Attack.h"

@interface LightningAttack : Attack
{

}

@end

#import "LightningAttack.h"


@implementation LightningAttack

@end


 

客户端调用

- (void)viewDidLoad
{
  [super viewDidLoad];
  
  // create a new avatar
  AttackHandler *avatar = [[[Avatar alloc] init] autorelease];
  
  // put it in metal armor
  AttackHandler *metalArmoredAvatar = [[[MetalArmor alloc] init] autorelease];
  [metalArmoredAvatar setAttackHandler:avatar];
  
  // then add a crytal shield
  // to the avatar who's in 
  // a metal armor
  AttackHandler *superAvatar = [[[CrystalShield alloc] init] autorelease];
  [superAvatar setAttackHandler:metalArmoredAvatar];
  
  // ... some other actions
  
  // attack the avatar with
  // a sword
  Attack *swordAttack = [[[SwordAttack alloc] init] autorelease];
  [superAvatar handleAttack:swordAttack];
  
  // then attack the avatar with
  // magic fire
  Attack *magicFireAttack = [[[MagicFireAttack alloc] init] autorelease];
  [superAvatar handleAttack:magicFireAttack];
  
  // now there is a new attack
  // with lightning...
  Attack *lightningAttack = [[[LightningAttack alloc] init] autorelease];
  [superAvatar handleAttack:lightningAttack];
  
  // ... further actions
}

 

第七部分

18模板方法

模板方法:定义一个操作中算法的骨架,而将一些步骤延迟到子类种中,模板方法使子类可以重定义算法的某些特定步骤而不改变该算法的结构。

使用场景:

需要一次性实现算法的不变部分,而将可变的行为留给子类来实现。

子类的共同行为应该被提取出来放到公共类中,以避免代码的重复。现有代码的差别应该被分离为新的操作。然后用一个调用这些新操作的木板方法来替换这些不同的代码。

需要控制子类的扩展。可以定义一个在特定点调用钩子操作的模板方法。子类可以通过对钩子操作的实现在这些点扩展功能。

制作三明治的例子来说

定义抽象基类,制作三明治的一般步骤

//AnySandwich.h


#import <Foundation/Foundation.h>


@interface AnySandwich : NSObject 
{

}

- (void) make;

// Steps to make a sandwich
- (void) prepareBread;
- (void) putBreadOnPlate;
- (void) addMeat;
- (void) addCondiments;
- (void) extraStep;
- (void) serve;

@end


//AnySandwich.m
#import "AnySandwich.h"


@implementation AnySandwich

- (void) make
{
  [self prepareBread];
  [self putBreadOnPlate];
  [self addMeat];
  [self addCondiments];
  [self extraStep];
  [self serve];
}

- (void) putBreadOnPlate
{
  // We need first to put bread on a plate for any sandwich.
}

- (void) serve
{
  // Any sandwich will be served eventually.
}

#pragma mark -
#pragma Details will be handled by subclasses

- (void) prepareBread
{
  
  [NSException raise:NSInternalInconsistencyException 
              format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}

- (void) addMeat
{
  [NSException raise:NSInternalInconsistencyException 
              format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}

- (void) addCondiments
{
  [NSException raise:NSInternalInconsistencyException 
              format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}

- (void) extraStep{}

@end

 

汉堡类

//Hamburger.h

#import <Foundation/Foundation.h>
#import "AnySandwich.h"

@interface Hamburger : AnySandwich 
{

}

- (void) prepareBread;
- (void) addMeat;
- (void) addCondiments;
//- (void) extraStep;

// Hamburger specific methods
- (void) getBurgerBun;
- (void) addKetchup;
- (void) addMustard;
- (void) addBeefPatty;
- (void) addCheese;
- (void) addPickles;

@end

//Hamburger.m

#import "Hamburger.h"


@implementation Hamburger

- (void) prepareBread;
{
  [self getBurgerBun];
}

- (void) addMeat
{
  [self addBeefPatty];
}

- (void) addCondiments
{
  [self addKetchup];
  [self addMustard];
  [self addCheese];
  [self addPickles];
}

#pragma mark -
#pragma mark Hamburger Specific Methods

- (void) getBurgerBun
{
  // A hamburger needs a bun.
}

- (void) addKetchup
{
  // Before adding anything to a bun, we need to put ketchup.
}

- (void) addMustard
{
  // Then add some mustard.
}

- (void) addBeefPatty
{
  // A piece of beef patty is the main character in a burger.
}

- (void) addCheese
{
  // Let's just assume every burger has cheese.
}

- (void) addPickles
{
  // Then finally add some pickles to it.
}

@end

热狗类

//Hotdog.h

#import <Foundation/Foundation.h>
#import "AnySandwich.h"

@interface Hotdog : AnySandwich 
{
  
}

- (void) prepareBread;
- (void) addMeat;
- (void) addCondiments;
//- (void) extraStep;

// Hotdog specific methods
- (void) getHotdogBun;
- (void) addWiener;
- (void) addKetchup;
- (void) addMustard;
- (void) addOnion;

@end

//Hotdog.m

#import "Hotdog.h"


@implementation Hotdog

- (void) prepareBread
{
  [self getHotdogBun];
}

- (void) addMeat
{
  [self addWiener];
}

- (void) addCondiments
{
  [self addKetchup];
  [self addMustard];
  [self addOnion];
}

#pragma mark -
#pragma mark Hotdog Specific Methods

- (void) getHotdogBun
{
  // First of all, we need a hotdog bun.
}

- (void) addWiener
{
  // A nice piece of wiener is the main character here.
}

- (void) addKetchup
{
  // Every hotdog needs ketchup.
}

- (void) addMustard
{
  // I think mustard is also needed.
}

- (void) addOnion
{
  // I think adding onion is a good idea.
}

@end

 

19策略

策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换。本模式使得算法可独立于使用它的客户而变化。

一个类在其操作中使用多个条件语句来定义许多行为。我们可以把相关的条件分支移到它们自己的策略类种功能。

需要算法的各种变体

需要避免把复杂的与算法相关的数据结构暴露给客户端。

- (BOOL)validateInput:(UITextField *)input error:(NSError **)error;

采用error参数可以传递错误信息,引用UITextField参数可以对输入框作相应的修改。

- (BOOL)validateInput:(UITextField*)input error:(NSError **)error{
    NSError *regError = nil;
    NSRegularExpression *regx = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:&regError];
    
    NSUInteger numberOfMatches = [regx numberOfMatchesInString:[input text] options:NSMatchingAnchored range:NSMakeRange(0, [[input text]length])];
    
    if (numberOfMatches == 0) {
        if (error != nil) {
            NSString *description =  NSLocalizedString(@"Input Validation Failed", @"") ;
            NSString *reason =   NSLocalizedString(@"The input can contain only numberic values", @"") ;
            NSArray *objArray = [NSArray arrayWithObjects:description,reason, nil];
            NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey,NSLocalizedFailureReasonErrorKey, nil];
            NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
            *error = [NSError errorWithDomain:@"InptValidationErrorDomain" code:1001 userInfo:userInfo];
        }
        return NO;
        
        
    }
    
    
    return YES;
    
    
    
}

 

如果直接调用汉堡的基类,会报错

//不可以直接调用抽象基类,会报错

 AnySandwich * sandwich = [[AnySandwich alloc] init];
 
 [sandwich make];



//具体的子类可以直接调用
    
   
 AnySandwich *hotdog = [[Hotdog alloc]init];
    
[hotdog make];

 

 

20命令

命令模式:将请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

想让应用程序支持撤销与恢复。

想用对象参数话一个动作以执行操作,并用不同命令对象来代替回调函数。

想要在不同的时刻对请求进行指定,排序和执行。

想记录修改日日志,这样在系统故障时,这些修改可在后来重做一遍。

想让系统支持事务,事务封装了对数据的一系列修改。事务可以建模为命令对象。

NSInvocation

NSUndoManager

第八部分 性能与对象访问

第21章享元模式

享元模式(Flyweight pattern): 运用共享技术有效地支持大量细粒度的对象。

当满足所有条件时,自然会考虑使用这个模式:

应用程序使用很多对象

在内存中保存对象会影响内存性能

对象的多数特有状态可以放到外部而轻量化

移除外在状态后,可以用较少的共享对象替代原来的那组对象。

应用程序不依赖于对象标识,因为共享对象不能提供唯一的标识。

 

百花池 效果

定义了一个FlowerView用来展示花朵

//FlowerView.h 文件

#import <Foundation/Foundation.h>
#import "UIKit/UIKit.h"

@interface FlowerView : UIImageView 
  
@end

//FlowerView.m 文件

#import "FlowerView.h"

@implementation FlowerView

- (void) drawRect:(CGRect)rect
{
  [self.image drawInRect:rect];
}

@end

 定义了一个工厂方法来产生FlowerView

//FlowerFactory.h


#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef enum 
{
  kAnemone,
  kCosmos,
  kGerberas,
  kHollyhock,
  kJasmine,
  kZinnia,
  kTotalNumberOfFlowerTypes
} FlowerType;

@interface FlowerFactory : NSObject 
{
  @private
  NSMutableDictionary *flowerPool_;
}

- (UIView *) flowerViewWithType:(FlowerType)type;

@end

//FlowerFactory.m

#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;
}

 

保存flowerview的状态

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>



@interface ExtrinsicFlowerState : NSObject
 

@property (nonatomic,strong) UIView *flowerView;

@property (nonatomic,assign) CGRect area;

@end


#import "ExtrinsicFlowerState.h"

@implementation ExtrinsicFlowerState

@end

 

控制器中调用代码

- (void)viewDidLoad {
    [super viewDidLoad];
    
 
    // construct a flower list
    FlowerFactory *factory = [[FlowerFactory alloc] init];
    NSMutableArray *flowerList = [[NSMutableArray alloc]
                                   initWithCapacity:500];
    
    
    for (int i = 0; i < 5000; ++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];
        
        // 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
    FlyweightView *flyWeightView = [[FlyweightView alloc]initWithFrame:CGRectMake(0, 0, 320, 640)];
  
  
    flyWeightView.backgroundColor = [UIColor orangeColor];
   
    [flyWeightView setFlowerList:flowerList];
 
    [self.view addSubview:flyWeightView];
 
    
    // Do any additional setup after loading the view, typically from a nib.
}

这样处理比直接在self.view 上添加 UIImageView还是节约了很多内存开销的,效果如下

22 代理

代理模式:为其它对象提供一种代理以控制对这个对象的访问。

需要一个远程代理,为处于不同地质空间或者网络中的对象提供本地带遍。

需要一个虚拟代理,为根据要求创建重型的对象。

需要一个保护代理,来控制不同访问权限对原对象的访问。

需要一个智能引用代理,通过对实体对象的引用来进行计数来管理内存。也能用户锁定实体对象,让其它对象不能修改它。

23备忘录

备忘录模式:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原来保存的状态。

Cocoa Touch NSKeyedArchiver NSKeyedUnarchiver

NSCoding 协议

 

 

 

 

参考资料

Pro Objective C Design Pattern for iOS Objective C编程之道iOS设计模式解析

https://github.com/iossvis/Objective-C-Design-Patterns-for-IOS----Carlo-Chung-book-s-code

 

 

© 著作权归作者所有

上一篇: Masonry技巧汇总
下一篇: YapDatabase的使用
云飞扬v5
粉丝 14
博文 105
码字总数 67465
作品 0
金华
私信 提问
如何判断你是合格的高级iOS开发工程师?

前言 随着移动互联网的高速发展泄洪而来,有意学习移动开发的人越来越多了,竞争也是越来越大,需要学习的东西很多。如何才能在激烈的移动开发者竞争中一枝独秀,成为一名真正合格的高级iOS...

_小迷糊
2018/05/26
0
0
移动开发之设计模式- 代理模式(IOS&Android)

资源 完全参照 代理模式|菜鸟教程但不包括IOS代码 代理模式 在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中,我们创建具有现有...

FlanneryZJ
2018/12/18
0
0
移动开发之设计模式-工厂模式(IOS&Android)

资源 完全参照 工厂模式|菜鸟教程 ,但不包括IOS代码 工厂模式 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳...

FlanneryZJ
2018/12/17
0
0
移动开发之设计模式- 命令模式(IOS&Android)

资源 完全参照 命令模式|菜鸟教程但不包括IOS代码 命令模式 命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用...

FlanneryZJ
2018/12/19
0
0
移动开发之设计模式-抽象工厂模式(IOS&Android)

资源 完全参照 抽象工厂模式|菜鸟教程 ,但不包括IOS代码 抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型...

FlanneryZJ
2018/12/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

重定向又是什么“垃圾”——教你再分类

  前言:之前写了几篇JSP的博客,现在又回过头来看Servlet,温故而知新,再回顾回顾,总会有收获的。以前学习Servlet感觉内容很多,现在看的时候,其实也没多少东西,只需知道Servlet的生命...

SEOwhywhy
20分钟前
0
0
一图胜千言!这10种可视化技术你必须知道

全文共4549字,预计学习时长9分钟 图片来源:Willian Justen deVasconcellos on Unsplash 相比于浩如烟海的数据表格,大部分人还是更喜欢视觉资料,这一点已不足为奇。也是出于这个原因,人们...

读芯术
24分钟前
1
0
Spring Boot 自动配置(auto-configurtion) 揭秘

本章,我们为你揭秘Spring Boot自动配置(Auto Configuration)运行机制,谈到auto-configuration,肯定离不开@EnableAutoConfiguration注解。 package org.springframework.boot.autoconfi...

爱编程的浪子
30分钟前
0
0
RabbitMQ延迟消息的延迟极限是多少?

之前在写Spring Cloud Stream专题内容的时候,特地介绍了一下如何使用RabbitMQ的延迟消息来实现定时任务。最近正好因为开发碰到了使用过程中发现,延迟消息没有效果,消息直接就被消费了的情...

程序猿DD
31分钟前
2
0
MySQL知识库语雀

类型:所有 MySQL知识库 MySQL知识库 06-05 20:57 近期阅读文章 近期已读或者未读文章列表 03-08 10:49 日常脚本 这里是平时工作会用到的一些常用的脚本,作为统一管理 03-08 05:09 培训 03...

rootliu
33分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部