IOS常见设计模式
介绍
设计模式(Design Pattern),是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结出来的固有模式。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络.
设计模式就如同建筑中的大厦的结构一般重要有精通了设计模式,才敢说真正理解了软件工程。可以说,设计模式是每一个架构师所必备的技能之一。作为一个面向对象设计程序员,只有精通了设计模式,才能摆脱码奴的命运,成为一个真正的软件工程师,才能完成自身价值的飞跃和设计思想的升华!
设计模式的分类
总体来说设计模式分为三大类:
创建型模式(Creational)
结构型模式(Structural)
行为型模式(Behavioral)
JAVA中的23设计模式
JAVA设计模式 Design Pattern | ||
创建型 Creational | 结构型 Structural | 行为型 Behavioral |
Abstract Factory(抽象工厂)Builder(建造者)Factory Method(工厂方法)Prototype(原型)Singleton(单态) | Adapter(适配器)Bridge(桥模式)Composite(组合)Decorator(装饰)Façade(外观)Flyweight(享元) Proxy(代理) | Chain of Responsibility(职责链)Command(命令)Interpreter(解释器)Iterator(迭代器)Mediator(中介)Memento(备忘录) Observer(观察者) State(状态) Strategy(策略) Template Method(模板方法) Visitor(访问者) |
IOS中常见8种设计模式
ios常见设计模式
Design Pattern
创建型
Creational
结构型
Structural
行为型
Behavioral
本文重点以IOS常见涉及模式为例. 更多涉及模式可以参考:设计模式 - 可复用面向对象软件的基础
单例模式(Singleton)
介绍
单例模式是IOS设计模式当中一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类(确保每个指定的类只存在一个实例对象)。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
单例模式核心
一般情况下只在第一次需要使用的时候初始化。
单例模式意义
如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
比如你生活在古代,你有几十个老婆,她们的老公都是你,你就是你们整个家的老公Sigleton,她们只要说道“老公”,都是指的同一个人,那就都是你.
系统中常见的单例模式
在iOS开发我们经常碰到只需要某类一个实例的情况,你的应用实例(UIApplication)必须有且只有一个,不然你是无法实行控制的,并且永远指你的当前应用.最常见的还是莫过于对硬件参数的访问类,比如UIAccelerometer.这个类可以帮助我们获得硬件在各个方向轴上的加速度,但是我们仅仅需要它的一个实例就够了,再多只会浪费内存.
UIAccelerometer
实例化方法+sharedAccelerometer,从名字上我们也能看出此方法让整个应用共享一个UIAccelerometer实例(PS:iOS 的开放中,我们往往能从方法名中就了解这个方法的作用)
UIApplication
提供了 +sharedAPplication方法创建和获取UIApplication单例
NSBundle
提供了 +mainBunle方法获取NSBundle单例
NSFileManager
提供了 +defaultManager方法创建和获得NSFileManager单例。(PS:有些时候我们得放弃使用单例模式,使用-init方法去实现一个新的实例,比如使用委托时)
NSNotificationCenter
提供了 +defaultCenter方法创建和获取NSNotificationCenter单例(PS:该类还遵循了另一个重要的设计模式:观察者模式)
NSUserDefaults
提供了 +defaultUserDefaults方法去创建和获取NSUserDefaults单例
所以苹果的SDK中大量的遵循此设计模式,那么它的内部是如何实现的呢?
单例模式代码
假设我们新建一个工具单例类:音乐播放器.
初级代码-使用懒汉式
因为主要体现一个实现的思想,所以代码写的比较细.
1.保证永远只alloc一次
// // BMMusicTool.m // // Created by 李 阳 on 15/8/5. // Copyright (c) 2015年 BirdMIchael. All rights reserved. // #import "BMMusicTool.h" @implementation BMMusicTool static BMMusicTool *_musicTool; // 引入全局变量,目的是整个文件都可以访问,并使用static修饰 + (instancetype)allocWithZone:(struct _NSZone *)zone { // 判断如果_musicTool如果有值就直接返回(永远只allocWithZone:一次) if (!_musicTool) { _musicTool = [super allocWithZone:zone]; } return _musicTool; } @end这里使用的是allocWithZone:方法,具体原因请见:[[Objective-C 里的 alloc 和 allocWithZone:]](http://birdmichael.com/index.php/2015/08/05/objective-cs-alloc-and-allocwithzone.html) 关于使用static修饰具体可以见:[[静变量static、全局变量extern、局部变量、实例变量]](http://birdmichael.com/index.php/2015/08/04/static-local-variables-global-variables-extern-static-variables-instance-variables.html) ##### 2.保证多线程只alloc一次
+ (instancetype)allocWithZone:(struct _NSZone *)zone { if (!_musicTool) { // 防止频繁加锁 // 多线程加锁 @synchronized(self){ // 判断如果_musicTool如果有值就直接返回(永远只allocWithZone:一次) if (!_musicTool) { // 防止多次创建 _musicTool = [super allocWithZone:zone]; } } } return _musicTool; }
3.规范代码,实现shared或者defaults方法
+ (instancetype)sharedMuiscTool { if (!_musicTool) { // 防止频繁加锁 @synchronized(self){ // 判断如果_musicTool如果有值就alloc一次.(避免在没allow得时候调用shared) if (!_musicTool) { // 防止创建多次 _musicTool = [[self alloc]init]; } } } return _musicTool; }> 提示:这里不能直接返回[[self alloc]init],不然每拿到一个对象都会初始化一次. ##### 4.保证copy后也是单例.
// 此方法为预留方法,在未来如果使用copy方法也不会产生新对象. - (id)copyWithZone:(NSZone *)zone { return _musicTool; }> 提示:能copy就保证再之前已经还有单例对象,所以不用判断_musicTool是否为空. ####
#import "BMMusicTool.h" @implementation BMMusicTool static BMMusicTool *_musicTool; // 引入全局变量,目的是整个文件都可以访问,并使用static修饰 + (void)load { _musicTool = [[self alloc]init]; } + (instancetype)allocWithZone:(struct _NSZone *)zone { // 判断如果_musicTool如果有值就直接返回(永远只allocWithZone:一次) if (!_musicTool) { // 防止多次创建 _musicTool = [super allocWithZone:zone]; } return _musicTool; } + (instancetype)sharedMuiscTool { return _musicTool; } - (id)copyWithZone:(NSZone *)zone { return _musicTool; } @end关于使用loade而不使用initialize查看此文有详细解释:[[Objective-C 类的加载和初始化(+load 和 +initialize 方法) ]](http://birdmichael.com/index.php/2015/08/05/loading-and-initialization-of-the-objective-c-class-load-and-initialize.html) > 所谓饿汉式就是程序一开始运行就执行代码创建. > > > 因为创建时在程序启动时,所以一般情况不会有多个线程进来创建,所以不需要加锁.并且调用shared时,肯定是在程序启动后. **饿汉式几乎完全不用.** #### 中级代码-使用GCD
#import "BMMusicTool.h" @implementation BMMusicTool static BMMusicTool *_musicTool; // 引入全局变量,目的是整个文件都可以访问,并使用static修饰 + (void)load { _musicTool = [[self alloc]init]; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _musicTool = [super allocWithZone:zone]; }); return _musicTool; } + (instancetype)sharedMuiscTool { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _musicTool = [[self alloc]init]; }); return _musicTool; } - (id)copyWithZone:(NSZone *)zone { return _musicTool; }> GCD默认dispatch_once只会执行一次,并且线程安全.更多可以参考[[ios多线程之NSThread,GCD,NSOperation以及线程同步]](http://birdmichael.com/index.php/2015/07/31/ios-multi-thread-nsthreadgcdnsoperation-and-thread-synchronization.html) 中GCD-一次性. #### 中级代码- MRC环境
#import "BMMusicTool.h" @implementation BMMusicTool static BMMusicTool *_musicTool; // 引入全局变量,目的是整个文件都可以访问,并使用static修饰 + (void)load { _musicTool = [[self alloc]init]; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _musicTool = [super allocWithZone:zone]; }); return _musicTool; } + (instancetype)sharedMuiscTool { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _musicTool = [[self alloc]init]; }); return _musicTool; } - (id)copyWithZone:(NSZone *)zone { return _musicTool; } -(oneway void)release { // Do nothing } - (instancetype)retain { return self; } -(NSUInteger)retainCount { return 1; } - (instancetype)autorelease { return self; } @end> 非ARC环境的核心就是:1.不release 2.不retain 3.retain计数器恒为1. 适配ARC和MRC
#if __has_feature(objc_arc) // ARC #else // MRC #endif
高级代码- 简化代码及宏实现<推荐
1.编写.h宏文件
命名为:BMSingleton.h
// // BMSingleton.h // // Created by 李 阳 on 15/8/5. // Copyright (c) 2015年 BirdMIchael. All rights reserved. // /* .h 引用 **/ #define BMSingletonH(name) + (instancetype)shared##name; /* .m 引用 **/ #if __has_feature(objc_arc) // ARC #define BMSingletonM(name) \ static id _instance; \ \ + (void)load \ { \ _instance = [[self alloc]init]; \ } \ \ + (instancetype)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \ } \ + (instancetype)shared##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc]init]; \ }); \ \ return _instance; \ } \ - (id)copyWithZone:(NSZone *)zone \ { \ return _instance; \ } // ARC结束 #else // MRC #define BMSingletonM(name) \ static id _instance; \ \ + (void)load \ { \ _instance = [[self alloc]init]; \ } \ \ + (instancetype)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \ } \ + (instancetype)shared##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc]init]; \ }); \ \ return _instance; \ } \ - (id)copyWithZone:(NSZone *)zone \ { \ return _instance; \ } \ - (instancetype)autorelease{return self;} \ - (oneway void)release{ } \ - (instancetype)retain{return self;} \ - (NSUInteger)retainCount{return 1;} // MRC结束 #endif
2.使用宏
.h中
#import <Foundation/Foundation.h> #import "BMSingleton.h" @interface BMMusicTool : NSObject BMSingletonH(MusicTool) @end
.m中
#import “BMMusicTool.h”
@implementation BMMusicTool
BMSingletonM(MusicTool)
@end
提示:BMSingletonH和BMSingletonM传入的name切记一样
这样只需要2句代码就使BMMusicTool这个类为单例了.并且自适应ARC和MRC.
下载源码:BMSingleton.h