一 iOS中都有什么设计模式?php
1.代理模式html
2.观察者模式ios
3.MVC模式算法
4.单例模式编程
5.策略模式swift
6.工厂模式设计模式
二 各个设计模式的做用?安全
(一)代理模式数据结构
在观察者模式中,一个对象任何状态的变动都会通知另外的对改变感兴趣的对象。这些对象之间不须要知道彼此的存在,这实际上是一种松耦合的设计。当某个属性变化的时候,咱们一般使用这个模式去通知其它对象。app
此模式的通用实现中,观察者注册本身感兴趣的其它对象的状态变动事件。当状态发生变化的时候,全部的观察者都会获得通知。苹果的推送通知(Push Notification)就是一个此模式的例子。
若是你要听从MVC模式的概念,你须要让模型对象和视图对象在不相互直接引用的状况下通讯。这正是观察者模式的用武之地。
Cocoa经过通知(Notifications)和Key-Value Observing(KVO)来实现观察者模式。
在cocoa框架中的Delegate模式中,委托人每每是框架中的对象(视图中的控件、表视图神马的),代理人每每是视图控制器对象。
在咱们这个例子中UITableView是委托人,代理人首先得知足一个条件:就是在.h文件中申明它拥有代理资格:
@interface WhateverViewController < UITableViewDelegate > @end
红色的表示这个视图控制器拥有UITableView的代理资格。
其次,在.m文件中定义委托人可让代理人去代替作的事情:
//视图控制器来代办应该有多少个节 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [NSArray count]; }
//视图控制器来代办某个节应该有多少行 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[NSArray objectAtIndex:section]count]; } // 视图控制器来代办负责每一个栏格的外观 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.textField.text = [NSArray objectAtIndex:indexPath.row]; return cell; } //负责当栏格被点击后须要触发的事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil]; [self.navigationController pushViewController:anotherViewController]; [anotherViewController release]; } // 这个是可选的,视图控制器勤快我就帮你代办,不勤快我就能够不帮你办这事儿,(提供哪些个行能够被编辑) - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return YES; }
// 对特定编辑风格进行操做 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { } }
// 可选,对那些被移动栏格做特定操做 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { }
// 对那些能够移动的行返回YES - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // 若是不想让栏格移动,就返回NO return YES; }
好了,当这个委托人须要办这些事时,代理人本身就站出来帮忙办了。这就是ios中的Delegate模式。
2、自定义的delegate模式
@interface A:UIView id transparendValueDelegate; @property(nomatic, retain) id transparendValueDelegate; @end @implementation A @synthesize transparendValueDelegate -(void)Call { NSString* value = @"你好"; [transparendValueDelegate transparendValue: value]; } @end
@interface B:UIView
NSString* value; @end
@implementation B -(void)transparendValue:(NSString*)fromValue { value = fromValue; NSLog(@"%@ ,我是B",value); } @end
使用时:
A* a = [[A alloc] init]; B* b = [[B alloc] init]; a. transparendValueDelegate = b;//设置A代理委托对象为B [a Call];
这样就会输出:
你好,我是B
委托模式关键就在于一个“被”字。这个B是很被动的,随时就会被你A Call一下。
3、为何会有delegate模式
换句话说,它能够用来解决神马问题?
当一个类的某些功能须要被别人来实现,可是既不明确是些什么功能,又不明确谁来实现这些功能的时候,委托模式就能够派上用场。
例如你能够再写个C类,实现-(void)transparendValue:(NSString*)fromValue {NSLog(@"%@ ,我是C",value); }也是彻底能够的。换谁来,只要它实现了这个方法,我就能够委托它来作这个事。
说到底一切都是为了使类之间的耦合性更松散。好的代码应该对扩展开放,对修改关闭。
总结来自http://blog.sina.com.cn/s/blog_b638dc89010192qu.html
(二)观察者模式
Observe
r从Subject
订阅通知,ConcreteObserver
实现重现ObServer
并将其重载其update
方法。一旦SubJect的实例须要通知Observer
任何新的变动,Subject
会发送update
消息来通知存储在其内部类中所注册的Observer
、在ConcreteObserver
的update
方法的实际实现中,Subject
的内部状态可被取得并进行后续处理。其类图以下:
Subject
容许其余观察者(实现了观察者接口的对象)对这个Subject
的改变进行请阅,当Subject
发送了变化,那么Subject
会将这个变化发送给全部的观察者,观察者就能对Subject
的变化作出更新。其时序图以下
Observer
来拓展Subject
的行为,这些Observer
具备处理存储在Subject中的信息的特定实现,这样也就实现了前面所说的消除不一样对象间的耦合的功能了。Cocoa Touch
框架中的的两种常常打交道的技术KVO
与通知都实现了观察者模式,因此下面咱们讨论的重点也就是基于这两个方面的。NSNotificationCenter
和NSNotification
对象实现了一对多的模型。经过NSNotificationCenter
可让对象之间进行通信,即使这些对象之间并不认识。下面咱们来看下NSNotificationCenter
发布消息的方法:NSNotification * subjectMessage = [ NSNotification notificationWithName:@"subjectMessage" object: self]; NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter]; [notificationCenter postNotification:subjectMessage];
subjectMessage
的NSNotification
对象,而后经过notificationCenter
来发布这个消息。经过向NSNotificationCenter
类发送defaulCenter
消息,能够获得NSNotificationCenter
实例的引用。每一个进程中只有一个默认的通知中心,因此默认的NSNotificationCenter
是个单例对象。若是有其余观察者定于了其对象的相关事件则能够经过如下的方法来进行操做:NSNotificationCenter * notificationCenter1 = [ NSNotificationCenter defaultCenter]; [notificationCenter addObserver: self selector: @selector(update:) name:@"subjectMessage" object: nil ];
update:
下面咱们能够实现如下这个方法- (void)update:(NSNotification*)notification{ if ([[notification name] isEqualToString:@"subjectMessage"]) { NSLog(@"%@",@"猴子派来的救兵去哪了?"); } }
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
Cocoa
提供的一种称为键值观察的机制,对象能够经过它获得其余对象特定属性的变动通知。而这个机制是基于NSKeyValueObserving
非正式些,Cocoa
经过这个协议为全部遵循协议的对象提供了一种自动化的属性监听的功能。通知
和KVO
均可以对观察者进行实现,可是他们之间仍是略有不一样的,由上面的例子咱们能够看出通知是由一个中心对象为全部观察者提供变动通知,主要是广义上关注程序事件,而KVO
则是被观察的对象直接想观察者发送通知,主要是绑定于特定对象属性的值。下面咱们经过一个简单的例子来了解下他的一些是使用方法Hero
这个模型@property (nonatomic,copy) NSString * name; @property (nonatomic,copy) NSString * title; @property (nonatomic,assign) NSUInteger age;
self.hero = [[Hero alloc] init]; self.hero.name = @"赵云"; self.hero.title = @"将军"; self.hero.age = 87;
name
监听下他的改变[self.hero addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ self.hero.name = @"张飞"; }
回调函
数中,处理收到的更改通知- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if([keyPath isEqualToString:@"name"]) { NSLog(@"赋值后--%@",self.hero.name); NSLog(@"新的值--%@",change[@"new"]); NSLog(@"之前的值--%@",change[@"old"]); } }
回调
打印以下:
注销
观察者- (void)dealloc{ [self.hero removeObserver:self forKeyPath:@"name"]; }
KVO
及通知
的内容就到这里,不过要知道这里谈及的只是最基础的用法,后面咱们可能仍是有更加深刻的探究,或者在后续中可能还会对比iOS中的代理以及Block
来探寻下iOS中的消息传递机制
,再或者像Swift
中的didSet
、willSet
的属性监听的方法,这些都是很好玩的内容,不是么?(三)MVC模式
MVC根据角色划分类,涉及到三个角色:
Model:模型保存应用程序的数据。
Controller:控制器是一个协调全部工做的中介者。它访问模型中的数据并在视图中展现它们,同时它们还监听事件和操做数据。
一个MVC模式的好的实现也就意味着每个对象都会被划分到上面所说的组中。
咱们能够很好的用下图来描述经过控制器实现的视图到模型的交互过程:
模型会把任何数据的变动通知控制器,而后控制器更新视图数据。视图对象通知控制器用户的操做,控制器要么根据须要来更新模型,要么检索任何被请求的数据。
你可能在想为何不能仅仅使用控制器,在一个类中实现视图和模型,这样貌似更加容易?
全部的这些都归结于代码关注点分离以及复用。在理想的状态下,视图应该和模型彻底的分离。若是视图不依赖某个实际的模型,那么视图就能够被复用来展现不一样模型的数据。
举个例子来讲,若是未来你打算加入电影或者书籍到你的资料库中,你仍然可使用一样的AlbumView去显示电影和书籍数据。更进一步来讲,若是你想建立一个新的与专辑有关联的工程,你能够很简单的复用Album类,由于它不依赖任何视图。这就是MVC的强大之处。
(四)单例模式
单例设计模式确保对于一个给定的类只有一个实例存在,这个实例有一个全局惟一的访问点。它一般采用懒加载的方式在第一次用到实例的时候再去建立它。
注意:苹果大量使用了此模式。例如:[NSUserDefaults standardUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager],全部的这些方法都返回一个单例对象。
你极可能会想为何这么关心是否一个类有多个实例?毕竟代码和内存都是廉价的,对吗?
有一些状况下,只有一个实例显得很是合理。举例来讲,你不须要有多个Logger的实例,除非你想去写多个日志文件。或者一个全局的配置处理类:实现线程安全的方式访问共享实例是容易的,好比一个配置文件,有好多个类同时修改这个文件。
(五)策略模式
在软件开发中也经常遇到相似的状况,实现某一个功能有多种算法或者 策略,咱们能够根据环境或者条件的不一样选择不一样的算法或者策略来完成该功能 。如查找、排序等,一种经常使用的方法是硬编码(Hard Coding)在一个类中,如须要提供多种查找算法,能够将这些算法写到一个类中,在该类中提供多个方法,每个方法对应一个具体的查找算法;固然也能够将这些查找算法封装在一个统一的方法中,经过if…else…或者 case 等条件判断语句来进行选择。这两种实现方法咱们均可以称之为硬编码,若是须要增长一种新的查找算法,须要修改封装算法类的源代码;更换查找算法,也须要修改客户端调用代码。在这个算法类中封装了大量查找算法, 该类代码将较复杂,维护较为困难。若是咱们将这些策略包含在客户端 ,这种作法更不可取,将致使客户端程序庞大并且难以维护,若是存在大量可供选择的算法时问题将变得更加严重。
例子1:一个菜单功能可以根据用户的“皮肤”首选项来决定是否采用水平的仍是垂直的排列形式。同事能够灵活增长菜单那的显示样式。
例子2:出行旅游:咱们 能够有几个策略能够考虑:能够骑自行车,汽车,作火车,飞机。每一个策略均可以获得相同的结果,可是它们使用了不一样的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度 。
如何让算法和对象分开来,使得算法能够独立于使用它的客户而变化?
策略模式: 定 义一系列的算法,把每个算法封装起来, 而且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 也称为 政策模式 (Policy) 。( Definea family of algorithms,encapsulate each one, andmake them interchangeable. Strategy lets the algorithmvary independently from clients that use it. )
策略模式把对象自己和运算规则区分开来,其 功能很是强大,由于这个设计模式自己的核心思想就是面向对象编程的多形性的思想。
当存在如下状况时使用Strategy模式
1)• 许多相关的类仅仅是行为有异。 “策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统须要动态地在几种算法中选择一种。
2)• 须要使用一个算法的不一样变体。例如,你可能会定义一些反映不一样的空间 /时间权衡的算法。当这些变体实现为一个算法的类层次时 ,可使用策略模式。
3)• 算法使用客户不该该知道的数据。可以使用策略模式以免暴露复杂的、与算法相关的数据结构。
4)• 一个类定义了多种行为 , 而且这些行为在这个类的操做中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
Strategy模式有下面的一些优势:
1) 相关算法系列
Strategy类层次为Context定义了一系列的可供重用的算法或行为。 继承有助于析取出这些算法中的公共功能。
2) 提供了能够替换继承关系的办法
: 继承提供了另外一种支持多种算法或行为的方法。你能够直接生成一个Context类的子类,从而给它以不一样的行为。但这会将行为硬行编制到 Context中,而将算法的实现与Context的实现混合起来,从而使Context难以理解、难以维护和难以扩展,并且还不能动态地改变算法。最后你获得一堆相关的类 , 它们之间的惟一差异是它们所使用的算法或行为。 将算法封装在独立的Strategy类中使得你能够独立于其Context改变它,使它易于切换、易于理解、易于扩展。
3) 消除了一些if else条件语句
:Strategy模式提供了用条件语句选择所需的行为之外的另外一种选择。当不一样的行为堆砌在一个类中时 ,很难避免使用条件语句来选择合适的行为。将行为封装在一个个独立的Strategy类中消除了这些条件语句。含有许多条件语句的代码一般意味着须要使用Strategy模式。4) 实现的选择
Strategy模式能够提供相同行为的不一样实现。客户能够根据不一样时间 /空间权衡取舍要求从不一样策略中进行选择。
Strategy模式缺点 :
1)客户端必须知道全部的策略类,并自行决定使用哪个策略类
: 本模式有一个潜在的缺点,就是一个客户要选择一个合适的Strategy就必须知道这些Strategy到底有何不一样。此时可能不得不向客户暴露具体的实现问题。所以仅当这些不一样行为变体与客户相关的行为时 , 才须要使用Strategy模式。
2 ) Strategy和Context之间的通讯开销
:不管各个ConcreteStrategy实现的算法是简单仍是复杂, 它们都共享Strategy定义的接口。所以极可能某些 ConcreteStrategy不会都用到全部经过这个接口传递给它们的信息;简单的 ConcreteStrategy可能不使用其中的任何信息!这就意味着有时Context会建立和初始化一些永远不会用到的参数。若是存在这样问题 , 那么将须要在Strategy和Context之间更进行紧密的耦合。3 )策略模式将形成产生不少策略类
:能够经过使用享元模式在必定程度上减小对象的数量。 增长了对象的数目 Strategy增长了一个应用中的对象的数目。有时你能够将 Strategy实现为可供各Context共享的无状态的对象来减小这一开销。任何其他的状态都由 Context维护。Context在每一次对Strategy对象的请求中都将这个状态传递过去。共享的 Strategy不该在各次调用之间维护状态。
例如,咱们在验证用户输入的表单的时候,加入包括电话输入框的验证和邮件输入框的验证,这两部分的验证算法是不一样的,若是把这个算法当作一个函数,他几乎有相同的输入参数和返回参数。咱们能够把这个相同的函数能够抽象为基类(InputValidator)的一个方法(bool validateInput(input,error)),而后抽象出两个具体的策略类:电话验证类(PhoneValidator)和邮件验证类(EmailValidator),他们须要在各自的实现里面去复写父类的验证方法。为了可以正常的调用到验证类的验证方法,咱们须要自定义一个UITextField的子类CustomTextField,其中有一个InputValidator类型的引用和一个validate方法,该方法里面调用InputValidator的验证方法,而后在textFieldDidEndEditing代理方法里面调用CustomTextField的validate方法,这样就不用咱们在判断输入是否合法的时候经过if else去处理每种逻辑,并且这样作方便扩展,提升可复用性。
实例:排序算法,NSArray的sortedArrayUsingSelector;经典的鸭子会叫,会飞案例。
(六)工厂模式
工厂模式个人理解是:他就是为了建立对象的
建立对象的时候,咱们通常是alloc一个对象,若是须要建立100个这样的对象,若是是在一个for循环中还好说,直接一句alloc就好了,可是事实并不那么如意,咱们可能会在不一样的地方去建立这个对象,那么咱们可能须要写100句alloc 了,可是若是咱们在建立对象的时候,须要在这些对象建立完以后,为它的一个属性添加一个固定的值,比方说都是某某学校的学生,那么可能有须要多些100行重复的代码了,那么,若是写一个-(void)createObj方法,把建立对象和学校属性写在这个方法里边,那么就是会省事不少,也就是说咱们能够alloc 建立对象封装到一个方法里边,直接调用这个方法就能够了,这就是简单工厂方法
代码结构以下
Animal 类
@interface Animal :NSObject
@proterty(nonatomic,strong) NSString *name;
-(void)laugh;
@end
Dog类
@interface Dog:Animal
@end
Cat类
@interface Cat:Animal
@end
建立对象的工厂类
.h
@interface AnimalFactory:NSObject
+(Dog *)createDog;
+(Cat *)createCat;
@end
.m
@implementation AnimalFactory
+(Dog *)createDog{
Dog *dog=[[Dog alloc]init];
dog.name=@“baby”;
return dog;
}
+(Cat *) createCat{
Cat *cat=[[Cat alloc]init];
return cat;
}
Main.m文件
Dog *dog=[AnimalFactory createDog];
Cat *cat=[AnimalFactory createCat];
这是简单工厂模式
如今建立100个Dog对象,若是这100个对象写在程序中的不一样地方,按上边的方法是须要把Dog *dog=[AnimalFactory createDog];这一句话写在程序中不少不一样的地方,那么如今有一个需求,就是若是须要把这些建立的100个Dog对象所有变成Cat对象,那么按照刚才的那个作法,就须要在这100句代码中把createDog方法变成createCat方法了,这样作仍是很复杂
那么这个时候用工厂方法模式就能解决这个难题了
工厂方法模式是为每个要建立的对象所在的类都相应地建立一个工厂
代码以下
@interface AnimalFactory:NSObject
-(Animal*)createAnimal;
@end;
Dog工厂类
@interface DogFactory:AnimalFactory;
@implementation DogFactory
-(Animal *)createAnimal{
retrurn [[Dog alloc]init];
}
@end
Cat工厂类
@interface CatFactory:AnimalFactory;
@implementation Cat Factory
-(Animal *)createAnimal
retrurn [[Cat alloc]init];
}
@end
Main.m
AnimalFactory *dogFactory=[[DogFactory alloc]init];
Animal *animal1=[dogFactory createAnimal];
[animal1 laugh];
Animal *animal2=[dogFactory createAnimal];
[animal2 laugh];
…….
Animal *animal100=[dogFactory createAnimal];
[animal100 laugh];
这样话若是要把100个Dog改成Cat的话,只须要吧DogFactory改成CatFactory就能够了