IOS设计模式

一、创建型模式

1.单例模式

static CSStudent *_student;
@implementation CSStudent
+ (CSStudent*)sharedCSStudent{
//    方法一
 staticdispatch_once_tonetoken;
    dispatch_once(&onetoken, ^{
_student= [[selfalloc]init];
    });
//    方法二
 @synchronized (self) {
 if(!_student){
            _student= [[CSStudentalloc]init];
        }
    }
 return _student;
}

2.三种工厂模式

2.1 简单工厂模式
  • 工厂角色:接受客户端的请求,通过请求负责创建相应的产品对象。
  • 抽象产品角色:是工厂模式所创建对象的父类或是共同拥有的接口。
  • 具体产品对象:工厂模式所创建的对象都是这个角色的实例。

工厂角色

SLFactory.h文件

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

typedef NS_ENUM(NSInteger,SLFactoryProductType){
    SLFactoryProductTypeMantou,
    SLFactoryProductTypeYoutiao,
};

NS_ASSUME_NONNULL_BEGIN

@interface SLFactory : NSObject
//工厂(Factory)角色:接受客户端的请求,通过请求负责创建相应的产品对象。
+ (SLOperation *)operationBreakfast:(SLFactoryProductType)breakfastType;
@end

NS_ASSUME_NONNULL_END
SLFactory.m 文件

#import "SLFactory.h"
#import "SFOperationMantou.h"
#import "SFOperationYoutiao.h"

@implementation SLFactory
+ (SLOperation*)operationBreakfast:(SLFactoryProductType)breakfastType{
    SLOperation *operation;
    switch (breakfastType) {
        case SLFactoryProductTypeMantou:
            operation = [[SFOperationMantou alloc]init];
            break;
        case SLFactoryProductTypeYoutiao:
            operation = [[SFOperationYoutiao alloc]init];
            break;
        default:
            return nil;
            break;
    }
    return operation;
}
@end

抽象产品角色:通过子类来获取具体的角色

SLOperation.h 文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SLOperation : NSObject

@property (nonatomic, copy, readonly)NSString *product;

- (void)productBreakfast;

@end

NS_ASSUME_NONNULL_END
SLOperation.m 文件

#import "SLOperation.h"

@implementation SLOperation
- (void)productBreakfast{}
@end

具体产品角色

SFOperationMantou.h 文件

#import "SLOperation.h"

NS_ASSUME_NONNULL_BEGIN

@interface SFOperationMantou : SLOperation
- (void)productBreakfast;
@end

NS_ASSUME_NONNULL_END
SFOperationMantou.m 文件

#import "SFOperationMantou.h"

@implementation SFOperationMantou

// 注意这里:@synthesize 重写setter,getter方法
@synthesize product = _product;

- (void)productBreakfast{
    _product = @"馒头";
}
@end
2.2 工厂方法模式

工厂方法使用OOP的多态性,将工厂和产品都抽象出一个基类,在基类定义统一的接口,然后在具体的工厂中创建具体的产品。

  • 抽象工厂角色:与应用程序无关,任何在模式中创建对象的工厂必须实现这个接口。
  • 具体工厂角色:实现了抽象工厂接口的具体类,含有与引用密切相关的逻辑,并且受到应用程序的调用以创建产品对象
  • 抽象产品角色:工厂方法所创建产品对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品角色:这个角色实现了抽象产品角色所声明的接口。工厂方法所创建的每个具体产品对象都是某个具体产品角色的实例。

抽象工厂角色

SLFactory2.h 文件

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

NS_ASSUME_NONNULL_BEGIN

@interface SLFactory2 : NSObject
+ (SLOperation2 *)createOperation;
@end

NS_ASSUME_NONNULL_END
SLFactory2.m 文件

#import "SLFactory2.h"

@implementation SLFactory2
+ (SLOperation2 *)createOperation{
    SLOperation2 *operation = [[SLOperation2 alloc]init];
    return operation;
}
@end

抽象产品角色

SLOperation2.h 文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SLOperation2 : NSObject
@property (nonatomic, copy, readonly)NSString *product;
- (void)productBreakfast;
@end

NS_ASSUME_NONNULL_END
SLOperation2.m 文件

#import "SLOperation2.h"

@implementation SLOperation2
- (void)productBreakfast{}
@end

具体工厂角色

SLFactoryMantou2.h  文件

#import "SLFactory2.h"

NS_ASSUME_NONNULL_BEGIN

@interface SLFactoryMantou2 : SLFactory2

@end

NS_ASSUME_NONNULL_END
SLFactoryMantou2.m  文件

#import "SLFactoryMantou2.h"
#import "SLOperationMantou2.h"

@implementation SLFactoryMantou2
+ (SLOperation2 *)createOperation{
    return [[SLOperationMantou2 alloc]init];
}
@end

具体产品角色

SLOperationMantou2.h  文件

#import "SLOperation2.h"

NS_ASSUME_NONNULL_BEGIN

@interface SLOperationMantou2 : SLOperation2
- (void)productBreakfast;
@end

NS_ASSUME_NONNULL_END
SLOperationMantou2.m  文件

#import "SLOperationMantou2.h"

@implementation SLOperationMantou2
@synthesize product = _product;
- (void)productBreakfast{
    _product = @"馒头";
}
@end
2.3 抽象工厂设计模式

所谓抽象工厂是指一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。

  • 抽象工厂角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
  • 具体工厂角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
  • 抽象产品角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或他们共同拥有的接口。
  • 具体产品角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这个客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。

抽象工厂角色

SLFactory3.h 文件

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

NS_ASSUME_NONNULL_BEGIN

@interface SLFactory3 : NSObject
typedef NS_ENUM(NSInteger,SLFactory3ProductType){
    SLFactory3ProductTypeMantou,
    SLFactory3ProductTypeYoutiao,
};
+ (instancetype)factoryWithType:(SLFactory3ProductType)type;
- (SLOperation3*)createProduct;
@end

NS_ASSUME_NONNULL_END
SLFactory3.m 文件

#import "SLFactory3.h"
#import "SLFactoryMantou.h"
#import "SLFactoryYoutiao.h"

@implementation SLFactory3
+ (instancetype)factoryWithType:(SLFactory3ProductType)type{
    SLFactory3 *factory;
    switch (type) {
        case SLFactory3ProductTypeMantou:
            factory = [[SLFactoryMantou alloc]init];
            break;
        case SLFactory3ProductTypeYoutiao:
            factory = [[SLFactoryYoutiao alloc]init];
            break;
        default:
            break;
    }
    return factory;
}
- (SLOperation3*)createProduct{
    return nil;
}
@end

抽象产品角色

SLOperation3.h 文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SLOperation3 : NSObject
@property (nonatomic, copy, readonly)NSString *product;
- (void)productBreakfast;
@end

NS_ASSUME_NONNULL_END
SLOperation3.m 文件

#import "SLOperation3.h"

@implementation SLOperation3
- (void)productBreakfast{}
@end

具体工厂角色

SLFactoryMantou.h 文件

#import "SLFactory3.h"

NS_ASSUME_NONNULL_BEGIN

@interface SLFactoryMantou : SLFactory3

@end

NS_ASSUME_NONNULL_END
SLFactoryMantou.m 文件

#import "SLFactoryMantou.h"
#import "SLOperationMantou3.h"

@implementation SLFactoryMantou
- (SLOperation3 *)createProduct{
    return [[SLOperationMantou3 alloc] init];
}
@end

具体产品角色

SLOperationMantou3.h 文件

#import "SLOperation3.h"

NS_ASSUME_NONNULL_BEGIN

@interface SLOperationMantou3 : SLOperation3

@end

NS_ASSUME_NONNULL_END
SLOperationMantou3.m 文件

#import "SLOperationMantou3.h"

@implementation SLOperationMantou3
@synthesize product = _product;
- (void)productBreakfast{
    _product = @"馒头";
}
@end

二、结构型模式

1.代理模式

用来处理事件的监听和参数传递。@required 必须实现这个协议方法;@optional可选实现。最好先判断方法是否实现:if(self.delegate && [self.delegate respondsToSelector:@selector(XXX)]){

delegate和block、Notification对比优缺点:delegate和block是一对一通信、block比delegate更加简洁清晰,但是如果通信事件较多时delegate运行成本较低且不易造成循环引用;通知合适一对多通信,注册通知要注意在合适的时间移除。

DelegateObj.h 文件

#import <Foundation/Foundation.h>

@protocol DelegateObjDelegate <NSObject>

@required //必须实现
- (void)delegateRequiredFunc:(id)obj;

@optional //可选实现
- (void)delegateOptionalFunc:(id)obj;

@end

NS_ASSUME_NONNULL_BEGIN

@interface DelegateObj : NSObject

@property (nonatomic, weak) id<DelegateObjDelegate> delegate;
- (void)func;

@end

NS_ASSUME_NONNULL_END
DelegateObj.m 文件

#import "DelegateObj.h"

@implementation DelegateObj
- (void)func{
    if(self.delegate && [self.delegate respondsToSelector:@selector(delegateRequiredFunc:)]){
        [self.delegate delegateRequiredFunc:nil];
    }
    if(self.delegate && [self.delegate respondsToSelector:@selector(delegateOptionalFunc:)]){
        [self.delegate delegateOptionalFunc:nil];
    }
}
@end

2.类簇

Foundation框架中广泛使用的设计模式,类簇在公共抽象超类下对多个私有的具体子类进行分组。以这种方式对类进行分组简化了面向对象框架的公共可见体系结构,而不会降低其功能丰富度。类簇是基于抽象工厂设计模式的

3.装饰模式

动用组合,少用继承
装饰者模式,是面向对象编程中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,装饰者模式相比成子类更为灵活,这样可以给某个对象而不是类添加一些功能。

咖啡饮料的价格 = 咖啡本身的价格 + 各种调料的价格
Espresso Macchiato(浓缩玛奇朵)的价格 = Espresso(浓缩咖啡) 的价格 +Milk(牛奶)的价格 + Mocha(摩卡)的价格。


咖啡本身的 Beverage 协议

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@protocol Beverage <NSObject>
@optional
- (NSString *)getName;
- (double)cost;
@end

NS_ASSUME_NONNULL_END

Espresso

Espresso.h 文件

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

NS_ASSUME_NONNULL_BEGIN

@interface Espresso : NSObject<Beverage>

@end

NS_ASSUME_NONNULL_END
Espresso.m 文件

#import "Espresso.h"

@implementation Espresso{
    NSString *_name;
}

- (instancetype)init{
    if (self = [super init]) {
        _name = @"Espresso";
    }
    return self;
}

-(NSString *)getName{
    return _name;
}

-(double)cost{
    return 1.99;
}

@end

各种调料的 CondimentDecorator 协议

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

NS_ASSUME_NONNULL_BEGIN

@protocol CondimentDecorator <Beverage>

@end

NS_ASSUME_NONNULL_END

Milk(牛奶)

Milk.h 文件

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

NS_ASSUME_NONNULL_BEGIN

@interface Milk : NSObject<CondimentDecorator>
@property (strong, nonatomic)id<Beverage> beverage;
- (instancetype)initWithBeverage:(id<Beverage>) beverage;
@end

NS_ASSUME_NONNULL_END
Milk.m 文件

#import "Milk.h"

@implementation Milk{
    NSString *_name;
}

- (instancetype)initWithBeverage:(id<Beverage>)beverage{
    if (self = [super init]) {
        _name = @"Milk";
        self.beverage = beverage;
    }
    return self;
}

- (NSString *)getName{
    return [NSString stringWithFormat:@"%@ + %@",[self.beverage getName],_name];
}

- (double)cost{
    return .30 + [self.beverage cost];
}

@end

Mocha(摩卡)

Mocha.h 文件

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

NS_ASSUME_NONNULL_BEGIN

@interface Mocha : NSObject<CondimentDecorator>
@property (strong, nonatomic) id<Beverage> beverage;
- (instancetype)initWithBeverage:(id<Beverage>) beverage;

@end

NS_ASSUME_NONNULL_END
Mocha.m 文件

#import "Mocha.h"

@implementation Mocha{
    NSString *_name;
}

- (instancetype)initWithBeverage:(id<Beverage>)beverage{
    if (self = [super init]) {
        self.beverage = beverage;
        _name = @"Mocha";
    }
    return self;
}

- (NSString *)getName{
    return [NSString stringWithFormat:@"%@ + %@",[self.beverage getName],_name];
}

- (double)cost{
    return .20 + [self.beverage cost];
}

@end

4.享元模式

享元模式主要用于减少同一类对象的大量创建,以减少内存占用,提高项目流畅度。ios中的UITableViewCell,及线程池 就用了享元模式。
两个关键:1.可共享的享元对象 2.享元池
工厂方法是这一角色的候选对象

FlowerFactory.h  文件

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

NS_ASSUME_NONNULL_BEGIN

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

NS_ASSUME_NONNULL_END

FlowerFactory.m  文件

#import "FlowerFactory.h"

@implementation FlowerFactory
- (Flower *)flowerViewWithType:(FlowerType)type{
    if(self.flowerPools == nil){
        self.flowerPools = [[NSMutableDictionary alloc]initWithCapacity:kTotalNumberFlower];
    }
    Flower *flower = [self.flowerPools objectForKey:[NSNumber numberWithInteger:type]];
    if(flower == nil){
        flower = [[Flower alloc]init];
        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;
        }
        [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
Flower.h   文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Flower : NSObject
@property (nonatomic, copy) NSString *flowerColor;
@property (nonatomic, copy) NSString *flowerName;
@end

NS_ASSUME_NONNULL_END

使用方法

#import "ShareEle/Flower.h"
#import "ShareEle/FlowerFactory.h"


FlowerFactory *factory = [[FlowerFactory alloc]init];
    
  NSMutableArray *arrayFlowers = [[NSMutableArray alloc]init];
    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];
     }

三、行为型模式

1.观察者模式

观察者模式 完美的将观察者和被观察者的对象分离开


普通属性

@property (nonatomic, assign) NSInteger num;

- (void)viewDidLoad {
    [super viewDidLoad];
    [self addObserver:self forKeyPath:@"num" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    self.num++;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if([keyPath isEqualToString:@"num"]){
        NSLog(@"%@-----%@",change[@"old"],change[@"new"]);
    }
}

观察的是数组集合类数组元素和个数的变化

@property (nonatomic, strong) NSMutableArray *numAry;

- (void)viewDidLoad {
    [super viewDidLoad];
   self.numAry = [NSMutableArray array];
    [self.numAry addObject:@(0)];
    [self addObserver:self forKeyPath:@"numAry" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}

static int indexNum = 1;

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self mutableArrayValueForKey:@"numAry"][0] = @(indexNum);
    indexNum++;
    NSLog(@"添加后数组:%@",self.numAry);
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if([keyPath isEqualToString:@"numAry"]){
        NSLog(@"%@-----%@",change[@"old"],change[@"new"]);
    }
}

观察的是数组中某一个元素的属性的变化

Person.h  文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject
@property (nonatomic, assign) int num;
@end

NS_ASSUME_NONNULL_END


调用文件
#import "Person.h"

@property (nonatomic, strong) NSMutableArray *numAry;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.numAry = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
        Person *person = [[Person alloc]init];
        person.num = i;
        [self.numAry addObject:person];
    }
    NSIndexSet *indexSet = [[NSIndexSet alloc]initWithIndex:2];
    [self.numAry addObserver:self toObjectsAtIndexes:indexSet forKeyPath:@"num" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}

static int indexNum = 1;

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    ((Person *)self.numAry[2]).num = indexNum;
    indexNum++;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if([keyPath isEqualToString:@"num"]){
        NSLog(@"监听变化:%@---%@",change[@"old"],change[@"new"]);
    }
}

2.命令模式

命令对象封装了如何对目标执行指令的信息,因此客户端或调用者不必了解目标的任何细节,却任可以对他执行任何已有的操作。通过把请求封装成对象,客户端可以把它参数化并置入队列或日志中,也能够支持可撤销操作。命令对象将一个或多个动作绑定到特定的接收器。命令模式消除了作为对象的动作和执行它的接收器之间的绑定。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容