设计模式
一种或几种被所有程序员广泛认同的,有某些特定功能,或者实现某些特殊作用的编码格式
单例模式
键值编码(KVC)
键值观察(KVO)
观察者模式()
工厂模式(工厂方法)
ps:MVC && MVVM && CVC
一、单例模式
1 #import2 3 /* 4 单例模式 5 1.通常情况下,一个工程只有一个单例类。 6 2.我们将一个类选中,将它作为单例类。 7 3.在整个工程中这个类所创建的对象是唯一并且不能被释放 8 9 作用:界面传值-在整个工程任意位置对单例对象的属性进行赋值10 也可以在整个工程的任意位置对单例对象的属性进行访问11 */12 @interface Globle : NSObject13 14 @property (strong, nonatomic) NSString *userId;15 16 // 单例方法17 // 作用:获取唯一单例对象18 + (Globle*) shareGloble;//getGloble19 20 @end21 22 #import "Globle.h"23 24 // 创建一个单例对象,用静态修饰符将这个对象的生命周期延长至整个工程25 static Globle *globle = nil;26 27 @implementation Globle28 29 +(Globle *)shareGloble30 {31 // 第一次执行单例方法,将单例对象初始化32 if (globle == nil) {33 globle = [[Globle alloc] init];34 globle.userId = @"";35 }36 // 之后的每次调用,都会直接返回上面的唯一单例对象37 return globle;38 }39 @end40 41 42 #import 43 #import "Globle.h"44 45 @interface People : NSObject46 47 +(void) showUserId;48 49 @end50 51 #import "People.h"52 53 @implementation People54 55 +(void)showUserId56 {57 NSLog(@"userId:%@",[Globle shareGloble].userId);58 }59 @end60 61 62 #import 63 #import "Globle.h"64 #import "People.h"65 66 int main(int argc, const char * argv[]) {67 @autoreleasepool {68 69 [Globle shareGloble].userId = @"1001";70 [People showUserId];71 72 }73 return 0;74 }
二、KVC
1 #import2 3 /* 4 KVC key-value-coding 5 6 作用:能够无视OC中关于私有的设定,直接通过底层赋值方式对属性赋值(和获取); 7 8 */ 9 @interface KVCClass : NSObject10 11 -(void) showProperty;12 13 @end14 15 #import "KVCClass.h"16 #import "Student.h"17 18 @interface KVCClass ()19 20 @property (strong, nonatomic) NSString *kvcProperty;21 @property (strong, nonatomic) Student *tempStu;22 23 @end24 25 @implementation KVCClass26 27 - (instancetype)init28 {29 self = [super init];30 if (self) {31 self.tempStu =[[Student alloc] init];32 }33 return self;34 }35 36 -(void)showProperty37 {38 NSLog(@"property:%@",self.kvcProperty);39 NSLog(@"property:%@",self.tempStu.name);40 41 }42 @end43 44 45 #import 46 47 @interface Student : NSObject48 49 @property (strong, nonatomic) NSString *name;50 51 @end52 53 #import "Student.h"54 55 @implementation Student56 57 @end58 59 60 #import 61 62 #import "KVCClass.h"63 int main(int argc, const char * argv[]) {64 @autoreleasepool {65 KVCClass *kvc = [[KVCClass alloc] init];66 67 //表示 在KVC对象中查找名字为[kvcProperty] 的属性,并对这个属性赋值为@“bowen”68 // 设置69 [kvc setValue:@"bowen" forKey:@"kvcProperty"];70 71 [kvc setValue:@"bowen1" forKeyPath:@"tempStu.name"];72 73 [kvc showProperty]; // 取值
NSLog(@"%@",[kvc valueForKey:@"kvcProperty"]);
74 NSLog(@"%@",[kvc valueForKeyPath:@"tempStu.name"]);75 }76 return 0;77 }
OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎。所以说有些事不是都是顺其自然的,而是需要的时候自然就诞生了。
下面就来看一下这种技术的使用:
Dog.h
- //
- // Dog.h
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface Dog : NSObject
- @end
Dog.m
- //
- // Dog.m
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Dog.h"
- @implementation Dog
- @end
定义了Dog这个类,但是什么都没有,他只是一个中间类,没什么作用,在这个demo中。
Person.h
- //
- // Person.h
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Dog.h"
- @interface Person : NSObject{
- @private
- NSString *_name;
- NSDog *_dog;
- NSInteger *age;
- }
- @end
Person.m
- //
- // Person.m
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Person.h"
- @implementation Person
- - (NSString *)description{
- NSLog(@"%@",_name);
- return _name;
- }
- @end
Person类中我们定义了两个属性,但是这两个属性对外是不可访问的,而且也没有对应的get/set方法。我们也实现了description方法,用于打印结果
看一下测试代码
main.m
- //
- // main.m
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Person.h"
- #import "Dog.h"
- //KVC:很暴力,及时一个类的属性是私有的,而且也没有get/set方法,同样可以读写
- //相当于Java中的反射,破坏类的封装性
- int main(int argc, const charchar * argv[]) {
- @autoreleasepool {
- Person *p = [[Person alloc] init];
- //设置值
- //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)
- [p setValue:@"jiangwei" forKey:@"name"];
- Dog *dog = [[Dog alloc] init];
- [p setValue:dog forKey:@"dog"];
- //KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法类似
- //读取值
- NSString *name = [p valueForKey:@"name"];
- //设置基本数据类型
- //这里需要将基本类型转化成NSNumber
- //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age
- [p setValue:@22 forKey:@"age"];
- NSLog(@"%@",p);
- return 0;
- }
- return 0;
- }
这里我们生成一个Person对象,然后开始使用KVC技术了:
1、设置属性值
- //设置值
- //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)
- [p setValue:@"jiangwei" forKey:@"name"];
- Dog *dog = [[Dog alloc] init];
- [p setValue:dog forKey:@"dog"];
使用setValue方法,就可以进行对属性进行设置值操作了,同时需要传递这个属性的名称,这个和Java中使用反射机制真的很像。
注:KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法一样
- //设置基本数据类型
- //这里需要将基本类型转化成NSNumber
- //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age
- [p setValue:@22 forKey:@"age"];
还有一个需要注意的地方:当我们在设置基本类型的时候,需要将其转化成NSNumber类型的。
2、取属性的值
- //读取值
- NSString *name = [p valueForKey:@"name"];
取值就简单了
下面再来看一下KVC中强大的功能:键值路径
键值路径是对于一个类中有数组对象的属性进行便捷操作。
看个场景:
一个作者有多本书
Author.h
- //
- // Author.h
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface Author : NSObject{
- NSString *_name;
- //作者出版的书,一个作者对应多个书籍对象
- NSArray *_issueBook;
- }
- @end
作者类中定义了名字和一个书籍数组
Author.m
- //
- // Author.m
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Author.h"
- @implementation Author
- @end
Book.h
- //
- // Book.h
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Author.h"
- @interface Book : NSObject{
- Author *_author;
- }
- @property NSString *name;
- @property floatfloat *price;
- @end
定义了一个作者属性,书的名字,价格
Book.m
- //
- // Book.m
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Book.h"
- @implementation Book
- @end
看一下测试代码
main.m
- //
- // main.m
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Book.h"
- #import "Author.h"
- int main(int argc, const charchar * argv[]) {
- @autoreleasepool {
- //------------------KVC键值路径
- /*
- Book *book = [[Book alloc] init];
- Author *author = [[Author alloc] init];
- //设置作者
- [book setValue:author forKey:@"author"];
- //设置作者的名字
- //路径为:author.name,中间用点号进行连接
- [book setValue:@"jiangwei" forKeyPath:@"author.name"];
- NSString *name = [author valueForKey:@"name"];
- NSLog(@"name is %@",name);
- */
- //--------------------KVC的运算
- Author *author = [[Author alloc] init];
- [author setValue:@"莫言" forKeyPath:@"name"];
- Book *book1 = [[Book alloc] init];
- book1.name = @"红高粱";
- book1.price = 9;
- Book *book2 = [[Book alloc] init];
- book2.name = @"蛙";
- book2.price = 10;
- NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];
- [author setValue:array forKeyPath:@"issueBook"];
- //基本数据类型会自动被包装成NSNumber,装到数组中
- //得到所有书籍的价格
- NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];
- NSLog(@"%@",priceArray);
- //获取数组的大小
- NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];
- NSLog(@"count=%@",count);
- //获取书籍价格的总和
- NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];
- NSLog(@"%@",sum);
- //获取书籍的平均值
- NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];
- NSLog(@"%@",avg);
- //获取书籍的价格最大值和最小值
- NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];
- NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];
- }
- return 0;
- }
1、首先通过前面说到的KVC设置作者的书籍数组
- //--------------------KVC的运算
- Author *author = [[Author alloc] init];
- [author setValue:@"莫言" forKeyPath:@"name"];
- Book *book1 = [[Book alloc] init];
- book1.name = @"红高粱";
- book1.price = 9;
- Book *book2 = [[Book alloc] init];
- book2.name = @"蛙";
- book2.price = 10;
- NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];
- [author setValue:array forKeyPath:@"issueBook"];
添加了两本书籍
2、下面就开始用到KVC中键值路径了
1)获取作者类中书籍数组中所有书籍的价格
- //基本数据类型会自动被包装成NSNumber,装到数组中
- //得到所有书籍的价格
- NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];
- NSLog(@"%@",priceArray);
看到了:@"issueBook.price" 这就是键值路径的使用,issueBook是作者类中的书籍数组属性名,price是书籍类的属性,中间用点号进行连接,这样我们就可以获取到了所有书籍的价格了,如果在Java中,我们需要用一个循环操作。但是OC中多么方便。
2)获取作者类中书籍数组的大小
- //获取数组的大小
- NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];
- NSLog(@"count=%@",count);
使用 @"issueBook.@count" 键值路径获取书籍数组的大小,issueBook是作者类中的书籍数组属性名,@count是特定一个写法,可以把它想象成一个方法,中间任然用点号进行连接
3)获取作者类中书籍数组的价格总和
- //获取书籍价格的总和
- NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];
- NSLog(@"%@",sum);
使用 @"issueBook.@sum.price" 键值路径获取书籍数组中的价格总和,issueBook是作者类中的书籍数组属性名,@sum是特性写法,可以把它想象成一个方法,price是书籍的价格属性名,可以把它看成是@sum的一个参数,中间用点号进行连接
如果在java中,这个需要用一个循环来计算总和,OC中很方便的
4)获取作者类中书籍数组的价格平均值、最小值、最大值
- //获取书籍的平均值
- NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];
- NSLog(@"%@",avg);
- //获取书籍的价格最大值和最小值
- NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];
- NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];
操作和上面类似,这里就不解释了
我们看到上面返回来的数据都是NSNumber类型的
三、观察者模式
1 #import2 3 /* 4 观察者模式(通知模式)NSNotification 5 观察者中心 NSNotificationCenter 6 7 注册观察者必需在[发出通知]之前 8 9 */10 11 @interface House : NSObject12 13 -(void) burn;14 15 @end16 17 #import "House.h"18 19 @implementation House20 21 -(void)burn22 {23 NSLog(@"房子着火了");24 // 发出通知25 [[NSNotificationCenter defaultCenter] postNotificationName:@"PlanB" object:nil];26 }27 @end28 29 #import 30 31 @interface Child : NSObject32 33 -(void) loudSay;34 35 -(void) toBeAGuanChazhe;36 37 @end38 39 #import "Child.h"40 41 @implementation Child42 43 -(void) loudSay44 {45 NSLog(@"报告:房子着火了");46 }47 48 -(void)toBeAGuanChazhe49 {50 // 创建观察者51 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loudSay) name:@"PlanB" object:nil];52 }53 @end54 55 #import 56 57 #import "House.h"58 #import "Child.h"59 60 61 int main(int argc, const char * argv[]) {62 @autoreleasepool {63 64 House *myhouse = [[House alloc] init];65 66 Child *mychild = [[Child alloc] init];67 68 // 让mychild 成为观察者69 [mychild toBeAGuanChazhe];70 71 // 让房子着火,发出PlanB现象72 [myhouse burn];73 }74 return 0;75 }
四、KVO
1 #import2 #import "JieCao.h" 3 4 /* 5 KVO key-value-observer(键值观察) 6 7 作用:能够在被观察的某个属性发生变化的时候,自动执行某些方法 8 9 当被观察的某个属性发生变化的时候,这个方法被自动回调10 11 -(void) observer...12 13 pss:当键值观察的观察者被使用完毕之后必须注销14 psss:键值观察是在[某个类中]给[某个属性] 注册观察者,当这个属性的值发生变化后作出响应模式15 16 */17 18 @interface Bowen : NSObject19 20 @property (strong,nonatomic) JieCao *my_jieCao;21 22 @end23 24 25 #import "Bowen.h"26 27 @implementation Bowen28 29 -(void) setMy_jieCao:(JieCao *)my_jieCao30 {31 _my_jieCao = my_jieCao;32 33 //注册观察者,观察_my_jieCao属性的值的变化34 [_my_jieCao addObserver:self forKeyPath:@"jieCaoValue" options:NSKeyValueObservingOptionNew context:nil];35 36 }37 // 不管在一个类当中注册一个多少KVO的观察者,本方法只能写一个38 -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context39 {40 if ([keyPath isEqualToString:@"jieCaoValue"]) {41 42 if ([[change objectForKey:@"new"] integerValue]<10) {43 NSLog(@"我要吐了,受不了老师了");44 }45 // NSLog(@"keyPath:%@",keyPath);46 // NSLog(@"Object:%@",keyPath);47 // NSLog(@"change:%@",[change objectForKey:@"new"]);48 49 }50 }51 - (void)dealloc52 {53 [_my_jieCao removeObserver:self forKeyPath:@"jieCaoValue"];54 }55 56 @end57 58 #import 59 60 @interface JieCao : NSObject61 62 @property (assign, nonatomic) NSInteger jieCaoValue;63 64 @end65 66 #import "JieCao.h"67 68 @implementation JieCao69 70 @end71 72 #import 73 74 #import "Bowen.h"75 #import "JieCao.h"76 77 int main(int argc, const char * argv[]) {78 @autoreleasepool {79 // 创建被观察属性80 JieCao *jieCao = [[JieCao alloc] init];81 jieCao.jieCaoValue = 100;82 // 创建观察对象83 Bowen *bowen = [[Bowen alloc] init];84 // 让观察对象开始观察[被观察属性]85 bowen.my_jieCao = jieCao;86 // 让被观察属性发生变化87 bowen.my_jieCao.jieCaoValue = 9;88 }89 return 0;90 }
五、工厂模式
1 #import2 #import "Fruit.h" 3 4 /* 5 6 工厂模式:(工厂方法) 7 8 个人理解:实际上就是用来快速大批量生产对象的 9 10 优点:能够将原本在本类初始化的对象,延时到子类中去初始化。实现了一个开放封闭原则。 11 12 */ 13 14 @interface FruitFactory : NSObject 15 16 // 通过外部输入的名字,创建[名字对应的类] 的对象 17 + (Fruit *)createFruitByName:(NSString *) name; 18 19 @end 20 21 #import "FruitFactory.h" 22 23 @implementation FruitFactory 24 25 +(Fruit *)createFruitByName:(NSString *)name 26 { 27 //需要知道名字对应的类 28 Class class = NSClassFromString(name); 29 // 创建想要的类对象 30 Fruit *fruit = [[class alloc] init]; 31 // 返回新建的[想要的类]的对象 32 return fruit; 33 } 34 @end 35 36 37 #import 38 39 @interface Fruit : NSObject 40 41 -(void) show; 42 43 @end 44 45 #import "Fruit.h" 46 47 @implementation Fruit 48 49 -(void)show 50 { 51 NSLog(@"I'm fruit"); 52 } 53 @end 54 55 #import "Fruit.h" 56 57 @interface Apple : Fruit 58 59 @end 60 61 62 #import "Apple.h" 63 64 @implementation Apple 65 66 -(void)show 67 { 68 NSLog(@"I'm apple"); 69 } 70 71 72 #import "Fruit.h" 73 74 @interface Banana : Fruit 75 76 @end 77 78 #import "Banana.h" 79 80 @implementation Banana 81 82 -(void)show 83 { 84 NSLog(@"I'm banana"); 85 } 86 87 @end 88 89 #import "Fruit.h" 90 91 @interface Pear : Fruit 92 93 @end 94 95 #import "Pear.h" 96 97 @implementation Pear 98 99 -(void)show100 {101 NSLog(@"I'm pear");102 }103 104 @end105 106 #import 107 #import "FruitFactory.h"108 109 int main(int argc, const char * argv[]) {110 @autoreleasepool {111 Fruit *fruit = [FruitFactory createFruitByName:@"Apple"];112 [fruit show];113 Fruit *fruit1 = [FruitFactory createFruitByName:@"Banana"];114 [fruit1 show];115 Fruit *fruit2 = [FruitFactory createFruitByName:@"Pear"];116 [fruit2 show];117 }118 return 0;119 }