常用的设计模式有MVC、单例、KVO、工厂、策略等。注意有人认为KVC也是属于设计模式,其实KVC是属性赋值的方式,跟设计模式无关。
大家一般对MVC、单例、KVO、工厂比较熟悉,对策略稍有生疏。下面我给大家一一梳理一下,有不对的地方请大家指正。
模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程序中。在iOS开发中MVC的机制被使用的淋漓尽致,充分理解iOS的MVC模式,有助于我们程序的组织合理性。
M 模型对象
模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算。例如,模型对象可能是表示游戏中的角色或地址簿中的联系人。用户在视图层中所进行的创建或修改数据的操作,通过控制器对象传达出去,最终会创建或更新模型对象。模型对象更改时(例如通过网络连接接收到新数据),它通知控制器对象,控制器对象更新相应的视图对象。
V 视图对象
视图对象是应用程序中用户可以看见的对象。视图对象知道如何将自己绘制出来,并可能对用户的操作作出响应。视图对象的主要目的,就是显示来自应用程序模型对象的数据,并使该数据可被编辑。尽管如此,在 MVC 应用程序中,视图对象通常与模型对象分离。在iOS应用程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的V。UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。
C 控制器对象
在应用程序的一个或多个视图对象和一个或多个模型对象之间,控制器对象充当媒介。控制器对象因此是同步管道程序,通过它,视图对象了解模型对象的更改,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。控制器对象解释在视图对象中进行的用户操作,并将新的或更改过的数据传达给模型对象。模型对象更改时,一个控制器对象会将新的模型数据传达给视图对象,以便视图对象可以显示它。对于不同的UIView,有相应的UIViewController,对应MVC中的C。例如在iOS上常用的UITableView,它所对应的Controller就是UITableViewController。
MVC之间的关系:
1.Model和View永远不能相互通信,只能通过Controller传递。
2.Controller可以直接与Model对话(读写调用Model),Model通过Notification和KVO机制与Controller间接通信。
3.Controller可以直接与View对话,通过outlet,直接操作View,outlet直接对应到View中的控件,View通过action向Controller报告事件的发生(如用户Touch我了)。Controller是View的直接数据源(数据很可能是Controller从Model中取得并经过加工了)。Controller是View的代理(delegate),以同步View与Controller。
首先看一下单例的例子:
/**
* 单例的写法常用的有三种方式:
方式1、不考虑线程
static SingleCase *manager = nil;
+ (SingleCase *)defaultManager {
if (!manager){
SingleCase = [[self alloc] init];
return manager;
}
}
方式2、考虑线程安全
+ (SingleCase *)sharedManager
{
static SingleCase *ManagerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
ManagerInstance = [[self alloc] init];
});
return ManagerInstance;
}
方式3、轻量级本地数据存储
NSUserDefaults *df = [NSUserDefaults standardUserDefaults];
//把auth 和uid写入本地
[df setObject:responseObject[M_Auth] forKey:M_Auth];
[df setObject:responseObject[M_Uid] forKey:M_Uid];
*/
IOS单例模式(singleton)
单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
1.单例模式的要点:
显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
2.单例模式的优点:
1.实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例。
2.灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程
IOS中的单例模式
在objective-c中要实现一个单例类,至少需要做以下四个步骤:
1、为单例对象实现一个静态实例,并初始化,然后设置成nil,
2、实现一个实例构造方法检查上面声明的静态实例是否为nil,如果是则新建并返回一个本类的实例,
3、重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例,
4、适当实现allocWitheZone,copyWithZone,release和autorelease。
下面以SurveyRunTimeData为例子:
static SurveyRunTimeData *sharedObj = nil; //第一步:静态实例,并初始化。
@implementation SurveyRunTimeData
+ (SurveyRunTimeData*) sharedInstance //第二步:实例构造检查静态实例是否为nil
{
@synchronized (self)
{
if (sharedObj == nil)
{
[[self alloc] init];
}
}
return sharedObj;
}
+ (id) allocWithZone:(NSZone *)zone //第三步:重写allocWithZone方法
{
@synchronized (self) {
if (sharedObj == nil) {
sharedObj = [super allocWithZone:zone];
return sharedObj;
}
}
return nil;
}
- (id) copyWithZone:(NSZone *)zone //第四步
{
return self;
}
- (id) retain
{
return self;
}
- (unsigned) retainCount
{
return UINT_MAX;
}
- (oneway void) release
{
}
- (id) autorelease
{
return self;
}
- (id)init
{
@synchronized(self) {
[super init];//往往放一些要初始化的变量.
return self;
}
}
@end
KVO Key-Value Observing 键值观察者模式,提供一种机制,当指定的对象的属性被修改后,则监听者就会接受到通知。就好像我们给手机定了一个闹钟,等到了制定的时间,闹钟就会响起,我们就会知道时间到了。这个过程中,我们就是监听者,闹钟就是被监听的对象
我们创建一个student类,使用KVO模式,给其中的username 属性添加监听者(观察者 XSStudent*su = [[XSStudentalloc]init]; su.name= @"zhangsan";
su.age = 12;
//Observer 观察者是谁
//KeyPath监听的属性,比如监听学生的name属性
//options :监听的内容
//NSKeyValueObservingOptionNew,NSKeyValueObservingOptionOld这两个参数的意思是监听它的新值和旧值
[su addObserver:self forKeyPath:@"name"options:NSKeyValueObservingOptionNsw|NSKeyValueObservingOptionOld context:nil];
//修改属性,触发方法 su.name= @"lis";
//观察者观察到有值发生改变的时候发生的方法
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
//change 字典中的old new 是关键字,专门用来存储新值和老值
NSLog(@"oldname %@",[changeobjectForKey:@"old"]);
NSLog(@"new %@",[change objectForKey:@"new"]);
}
注意,这里(NSString*)keyPath 传过来的就是你添加观察者的时候创建的key ,如果想要监听多个属性,你可以根据整个值来判断到底是哪个值的变化触发了该方法
一般是大批量生产零件的地方,在IOS中,工厂设计模式表示我们可以将一类控件提出来(使用静态方法),方便后期统一修改。其实这个也是大家常用的。如以下代码:
//定义工厂类,将常用的控件涉及到的属性用静态方法做一归纳总结,方便统一修改
//UIView
+ (UIView *)createViewWithFrame:(CGRect)frame;
//UILabel
+ (UILabel *)createLabelWithFrame:(CGRect)frame text:(NSString *)text textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor font:(UIFont *)font textAlignment:(NSTextAlignment)textAlignment;
//UIButton
+ (UIButton *)createButtonWithFrame:(CGRect)frame title:(NSString *)title titleColor:(UIColor *)titleColor backgroundColor:(UIColor *)backgroundColor type:(UIButtonType)type target:(id)target selector:(SEL)selector;
//UIImageView
+ (UIImageView *)createImageViewWithFrame:(CGRect)frame imageName:(NSString *)imageName;
//UITextField
+ (UITextField *)createTextFieldWithFrame:(CGRect)frame text:(NSString *)text placeholder:(NSString *)placeholder;
同一个问题可以有多个解决办法,我们可以将这个多个解决办法封装成不同的方法,我们在使用的时候根据自己的需要选择合适的方法。选择其中一种方法,对其他的方法是没有影响的,我们把这个过程叫做策略设计模式。
这样可能还是不太好理解,我们举个例子,出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机 ,当然你也可以选择步行。每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度 。
iOS应用分析
例如,我们在验证用户输入的表单的时候,加入包括电话输入框的验证和邮件输入框的验证,这两部分的验证算法是不同的,如果把这个算
法看成一个函数,他几乎有相同的输入参数和返回参数。我们可以把这个相同的函数可以抽象为基类(InputValidator)的一个方法(bool
validateInput(input,error)),然后抽象出两个具体的策略类:电话验证类(PhoneValidator)和邮件验证类
(EmailValidator),他们需要在各自的实现里面去复写父类的验证方法。为了能够正常的调用到验证类的验证方法,我们需要自定义一个
UITextField的子类CustomTextField,其中有一个InputValidator类型的引用和一个validate方法,该方法里
面调用InputValidator的验证方法,然后在textFieldDidEndEditing代理方法里面调用CustomTextField的
validate方法,这样就不用我们在判断输入是否合法的时候通过if else去处理每种逻辑,而且这样做方便扩展,提高可复用性。
今天先到这里,还要回去写程序,有空再来。