iOS设计模式一(工厂,生成器,单例)

简而言之,设计模式是为特定场景下的问题而定制的解决方案.
特定场景指问题所在的重复出现的场景.
问题指特定环境下你想达成的目标.

iOS设计模式解析,这是本有味道的书

本文主要为创建对象--获取源码

目录
1.原型模式
2.(具体)工厂方法模式
3.抽象工厂模式
3.1类簇
4.生成器模式
5.单例模式


1.原型模式

我认为就是"copy",
也就是说无需自己动手定义一个类来创建对象,直接拿来别的对象copy一下,产生个同一类型的新的对象使用
使用的时候要注意深复制(内存复制),而不是浅复制(指针复制)

*浅复制就是指针复制 出现两个指针 一块地址空间 旧指针和复制指针指向同一块地址空间 
如果源地址数据改变 那么两个指针指向的值就会改变 
深复制就是指针与空间同时复制  出现两个指针 两块地址空间 互不影响 
如果源地址数据变化 复制指针与空间不受影响。  

*对于系统的非容器类对象,我们可认为,
如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutbleCopy就是对象复制(深拷贝)
如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

1)对非集合类:
 [Object copy] // 浅复制
 [Object mutableCopy] //深复制
 [mutableObject copy] //深复制
 [mutableObject mutableCopy] //深复制
         
2)对集合类:
[Object copy] // 浅复制
[Object mutableCopy] //单层深复制
(即仅对对象本身进行深复制,对象元素仍是浅复制(指针拷贝,内存地址不变))
[mutableObject copy] //单层深复制
[mutableObject mutableCopy] //单层深复制

iOS深拷贝与浅拷贝、NSString内存分配
NSString深浅复制的见解


2.(具体)工厂方法模式

NSNumber的工厂方法

numberWithBool方法返回的实际对象类型是NSCFBoolean类型

调用类的工厂方法,接受不同类型的参数,返回该类的对象实例,并决定实例化何种私有具体类
(这也是我们在外部无法直接定义NSCFBoolean类型的原因)

所以叫做"具体工厂方法模式"更加贴切,
各种私有子类重写或重载父类中声明的公有工厂方法,并用这个方法创建自己特色的对象
比如上述工厂方法,创建的NSNumber对象,NSCFBoolean等都是NSNumber的具体工厂子类,子类是具体工厂


3.抽象工厂模式

3.1类簇

提到抽象工厂模式不得不说类簇,类簇是基于抽象工厂模式的思想,也有人说类簇就是一个抽象工厂模式的iOS版本的实现

在上面说过"各种私有子类重写或重载父类中声明的公有工厂方法,并用这个方法创建自己特色的对象",
而这个"声明公有工厂方法"的父类,就是"抽象工厂",再加上"具体工厂"私有子类,这个集合就是"类簇"

它在外层提供了很多方法接口,但是这些方法的实现是由具体的内部类来实现的.当使用NSNumber生成一个对象时,初始化方法会判断哪个“自己内部的类”最适合生成这个对象,然后这个“具体工厂”就会生成这个具体 的类对象返回给你
常见的类簇有NSArray,NSNumber,NSString...

这种由外层类提供统一抽象的接口,然后具体实现让隐藏的,具体的内部类来实现,在设计模式中称为“抽象工厂”模式

扩展:
使用类簇巧妙配置app语言版本:iOS 类簇(Class Cluster)使用心得
类簇
从NSArray看类簇


4.生成器模式

生成器模式就是定义基本属性与组合属性分离,
指导者-生成器-产品
指导者知道生成器应该建造什么产品
生成器知道以什么逻辑建造产品
(构建对象有很多种方式,如果组合对象属性的逻辑全在构建对象的类方法中,那会出现一大片的if-else或者switch-case,结构会很难看)


这种模式最适合用在构建复杂模型的游戏当中
下面就用构建游戏角色属性的方式展示此模式的优点
(建议看源码,一目了然)
(OSZ为oldSixZhu缩写)

基本属性.h:

#import <Foundation/Foundation.h>

@interface OSZCharacter : NSObject
//任何一个角色都有的基本属性

//身高,影响血量
@property (nonatomic, assign) float height;
//体重,影响血量
@property (nonatomic, assign) float weight;
//血量
@property (nonatomic, assign) float blood;
//速度,影响攻击力
@property (nonatomic, assign) float speed;
//力量,影响攻击力
@property (nonatomic, assign) float power;
//攻击力
@property (nonatomic, assign) float attack;

@end

基本属性.m:

#import "OSZCharacter.h"

@implementation OSZCharacter

//初始化下基本属性(统一设置所有模型最低属性值)
-(instancetype)init
{
    if (self = [super init])
    {
        self.height = 0;
        self.weight = 0;
        self.blood = 0;
        self.speed = 0;
        self.power = 0;
        self.attack = 0;
    }
    return self;
}

@end

生成器基类.h:

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

@interface OSZCharacterBuilder : NSObject

@property (nonatomic, strong) OSZCharacter *character;

//character并不知道如何构建一个有意义的属性
//本模型基于character构建有意义的角色属性
- (OSZCharacterBuilder *)buildNewCharacter;
- (OSZCharacterBuilder *)buildHeight:(float)value;
- (OSZCharacterBuilder *)buildWeight:(float)value;
- (OSZCharacterBuilder *)buildSpeed:(float)value;
- (OSZCharacterBuilder *)buildPower:(float)value;

@end

生成器基类.m:

#import "OSZCharacterBuilder.h"

@implementation OSZCharacterBuilder

- (OSZCharacterBuilder *)buildNewCharacter
{
    self.character = [[OSZCharacter alloc]init];
    return self;
}

- (OSZCharacterBuilder *)buildHeight:(float)value
{
    self.character.height = value;
    return  self;
}
- (OSZCharacterBuilder *)buildWeight:(float)value
{
    self.character.weight = value;
    return  self;
}
- (OSZCharacterBuilder *)buildSpeed:(float)value
{
    self.character.speed = value;
    return  self;
}
- (OSZCharacterBuilder *)buildPower:(float)value
{
    self.character.power = value;
    return  self;
}

@end

实际使用的生成器.h:

#import "OSZCharacterBuilder.h"

@interface OSZStandardCharacterBuilder : OSZCharacterBuilder

//重载下父类的方法,加工真正角色的属性逻辑
//加入身高体重对血量影响的逻辑
//速度力量对攻击力影响的逻辑
- (OSZCharacterBuilder *)buildHeight:(float)value;
- (OSZCharacterBuilder *)buildWeight:(float)value;
- (OSZCharacterBuilder *)buildSpeed:(float)value;
- (OSZCharacterBuilder *)buildPower:(float)value;

@end

实际使用的生成器.m:

#import "OSZStandardCharacterBuilder.h"

@implementation OSZStandardCharacterBuilder

- (OSZCharacterBuilder *)buildHeight:(float)value
{
    //1点身高加10点血
    self.character.blood += 10 * value;
    //处理过后用新值更新目标角色,然后将自身返回
    return  [super buildHeight:value];
}

- (OSZCharacterBuilder *)buildWeight:(float)value
{
    //1点体重加100点血
    self.character.blood += 100 * value;
    return  [super buildWeight:value];
}

- (OSZCharacterBuilder *)buildSpeed:(float)value
{
    //1点速度加10点攻击力
    self.character.attack += 10 * value;
    return  [super buildSpeed:value];
}

- (OSZCharacterBuilder *)buildPower:(float)value
{
    //1点力量加100点攻击力
    self.character.attack += 100 * value;
    return [super buildPower:value];
}

@end

指导者.h:

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

@interface OSZBuildRole : NSObject

//指导者 指导 生成器 创建返回产品 
//把加工过的属性组合起来成为一个具体的角色
//创建玩家
- (OSZCharacter *)createPlayer:(OSZCharacterBuilder *)builder;
//创建boss
- (OSZCharacter *)createBoss:(OSZCharacterBuilder *)builder;

@end

指导者.m:

#import "OSZBuildRole.h"

@implementation OSZBuildRole

- (OSZCharacter *)createPlayer:(OSZCharacterBuilder *)builder
{
    //初始化
    [builder buildNewCharacter];
    //加工
    [builder buildHeight:1];
    [builder buildWeight:10];
    [builder buildSpeed:1];
    [builder buildPower:10];
    //返回加工过的具体属性模型
    return builder.character;
    
}

- (OSZCharacter *)createBoss:(OSZCharacterBuilder *)builder
{
    
    [builder buildNewCharacter];
    
    [builder buildHeight:10];
    [builder buildWeight:100];
    [builder buildSpeed:10];
    [builder buildPower:100];
    
    return builder.character;
}


@end

c层.m代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    //生成器
    OSZStandardCharacterBuilder *characterBuilder = [[OSZStandardCharacterBuilder alloc]init];
    //指导者
    OSZBuildRole *role = [[OSZBuildRole alloc]init];
    //产品
    OSZCharacter *player = [role createPlayer:characterBuilder];
    OSZCharacter *boss = [role createBoss:characterBuilder];
    
    NSLog(@"%@\n%@",player,boss);
}
玩家属性
boss属性
在这些情形会想到使用该模式

5.单例模式

单例类只会开辟一次内存空间,总是返回自己的同一个实例,它提供了对类的对象所提供的资源的全局访问点.与这类设计相关的设计模式称为单例模式

单例模型OSZSingleton.h:

#import <Foundation/Foundation.h>
#import "singleton.h"
@interface OSZSingleton : NSObject
//测试属性
@property (nonatomic, copy) NSString *name;

//使用宏
singleton_h(OSZSingleton)
//+ (OSZSingleton *)sharedOSZSingleton;
@end

OSZSingleton.m:

#import "OSZSingleton.h"

@implementation OSZSingleton

//使用宏
singleton_m(OSZSingleton)

//static OSZSingleton *_singleton = nil;

//+ (OSZSingleton *)sharedOSZSingleton
//{
//    return [[self alloc] init];
//}

//直接重写allocWithZone,防止有人不明白此类为单例类
//alloc是用设为NULL的allocWithZone来调用的
//检查类的唯一实例是否已创建,如果没有,就创建新的实例并返回

//普通实现
//+(instancetype)allocWithZone:(struct _NSZone *)zone
//{
//    if (!_singleton)
//    {
//        _singleton = [super allocWithZone:zone];
//    }
//    return _singleton;
//}

//防止多线程访问,互斥锁
//+ (instancetype)allocWithZone:(struct _NSZone *)zone {
//    @synchronized (self) {
//        if (!_singleton) {
//            _singleton = [super allocWithZone:zone];
//        }
//    }
//    return _singleton;
//}

//或者GCD一次性执行函数
//+ (instancetype)allocWithZone:(struct _NSZone *)zone {
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        _singleton = [super allocWithZone:zone];
//    });
//    return _singleton;
//}

// 如果这个单例遵守了NSCopying和NSMutableCopying协议,
// 那么无论是使用copy方法还是mutableCopy方法, 都只会得到同一个实例对象
//- (id)copyWithZone:(NSZone *)zone {
//    return _singleton;
//}
//
//- (id)mutableCopyWithZone:(NSZone *)zone {
//    return _singleton;
//}

//MRC要重写以下四个方法
//- (instancetype)autorelease
//{
//    return _singleton;
//}
//
//- (instancetype)retain
//{
//    return _singleton;
//}
//
//- (oneway void)release
//{
//    
//}
//
//- (NSUInteger)retainCount
//{
//    return 1;
//}

@end

控制器OSZTwoVC.m:

#import "OSZTwoVC.h"
#import "OSZSingleton.h"

@interface OSZTwoVC ()
@end

@implementation OSZTwoVC

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blueColor];
    
    OSZSingleton *cat1 = [[OSZSingleton alloc]init];
//    NSLog(@"%lu",(unsigned long)cat1.retainCount);
    cat1.name = @"猫猫";
    NSLog(@"%@",cat1.name);
//    [cat1 release];
//    NSLog(@"%lu",(unsigned long)cat1.retainCount);
    
    OSZSingleton *cat2 = [[OSZSingleton alloc]init];
    NSLog(@"%@",cat2.name);
    //无论我们创建多少次对象,都是猫猫
}
@end

最后封装的单例宏singleton.h:


#if __has_feature(objc_arc)
#define singleton_h(name) +(instancetype)shared##name;

#define singleton_m(name) static id _instanceType;\
+(instancetype)shared##name\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instanceType = [[self alloc]init];\
});\
return _instanceType;\
}\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instanceType = [super allocWithZone:zone];\
});\
return _instanceType;\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instanceType;\
}
#else
#define singleton_h(name) +(instancetype)shared##name;

#define singleton_m(name) static id _instanceType;\
\
+(instancetype)shared##name\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instanceType = [[self alloc]init];\
});\
return _instanceType;\
}\
\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instanceType = [super allocWithZone:zone];\
});\
return _instanceType;\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instanceType;\
}\
\
-(instancetype)autorelease\
{\
    return _instanceType;\
}\
\
-(instancetype)retain\
{\
    return _instanceType;\
}\
\
-(oneway void)release\
{\
  \
}\
\
-(NSUInteger)retainCount\
{\
    return 1;\
}

#endif

下一节iOS设计模式二(适配器,桥接,外观)

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

推荐阅读更多精彩内容