1.工厂模式
工厂模式通常被分为简单工厂和抽象工厂,我就不区分了,这里举几个在开发中使用工厂方法的例子。
1.系统框架中类簇的实现,它将若干相关的私有具体工厂子类集合到一个公有的抽象超类之下。比如说NSNumber就是一个高度抽象的工厂,它和它的子类构成了一个类簇。NSNumber有很多子类,比如整数、浮点数、布尔数等等。所以NSNumber成为了这些类的超类。
我们可以使用NSNumber提供的类方法,初始化不同类型的数。
NSNumber*boolNumber = [NSNumbernumberWithBool:YES];
NSNumber*intNumber = [NSNumbernumberWithInt:10];
NSNumber*floatNumber = [NSNumbernumberWithFloat:10.0];
NSNumber*doubleNumber = [NSNumbernumberWithDouble:10.0];
NSNumber有一系列公有API,定义了各种类型的数所共有的行为。客户端在使用时无需知道NSNumber实例的具体类型。
2.第二个应用是在显示不同类型的cell时,我们可以声明一个BaseModel类,不同类型的model继承于这个类,接受服务器传来的不同类型的数据。我们也可以声明一个BaseCell类,显示不同数据的cell也都继承于这个类,有自己的布局方式。
我们在BaseModel里写一个便利构造方法,根据传进来的dictionary中的key值初始化不同的子类对象。
+ (instancetype)initWithDictionary:(NSDictionary *)dictionary{
// 先使用当前类(父类)创建出model对象
BaseModel *model = nil;
// 根据字典中key对应的数据初始化不同的子类对象并将其返回给我们的父类
if ([dictionary[@"tag"] isEqualToString:@"news"]) {
model = [[News alloc] init];
} else if ([dictionary[@"tag"] isEqualToString:@"images"]){
model = [[Images alloc] init];
} else if([dictionary[@"tag"] isEqualToString:@"music"]){
model = [[Music alloc] init];
}
[model setValuesForKeysWithDictionary:dictionary];
return model;
}
在加载数据源的时候,利用这个方法,把不同的model加载到数据源里。
for (NSDictionary *dic in arr) {
BaseModel *model = [BaseModel initWithDictionary:dic];
// 将不同子类创建出的model对象添加到我们的数组当中
[_dataArray addObject:model];//这些model其实是属于不同的子类的
}
在为cell加载数据的时候,我们可以取出_dataArray中的数据,并判断是哪一种类型的model,根据model去加载对应类型的cell。
// 根据我们的indexPath.row获取我们对应的model
BaseModel *baseModel = [self.dataArray objectAtIndex:indexPath.row];
// 根据取出来的model获取其对应的类名
NSString *modelName = [NSString stringWithUTF8String:object_getClassName(baseModel)];
// 根据不同的唯一标识重用不同的cell
BaseCell *cell = [tableView dequeueReusableCellWithIdentifier:modelName];
if (cell == nil) { // 根据我们每行提供的model创建出对应的cell // 根据不同需求生产不同的产品
cell = [BaseCell initWithModel:baseModel]; }这个方法是我们重写的
在baseCell里重写这个方法
+ (instancetype)initWithModel:(BaseModel *)model
{
//根据我们的OC函数获取我们的model类名并将其转化为OC字符串
NSString *modelName = [NSString stringWithUTF8String:object_getClassName(model)];
//使用model的类名拼接一个"Cell"来获取到我们的Cell类名
NSString *cellName = [modelName stringByAppendingString:@"Cell"];
//根据我们所提供的cellName来获取其对应的“cell子类”初始化一个cell对象返回给我们的父类对象
//唯一标识符可以使用我们所提供的model来给予不同cell所对应的标识来重用。
BaseCell *cell = [[NSClassFromString(cellName) alloc]initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:modelName];
相当于[NewsCell alloc]initWithStyle...
return cell;
}
我们在每个cell的子类里又重写了- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier方法,按照自己cell的特点去添加子视图和布局。
所以我们就做到了按照model名称去加载不同类型的数据,并加载对应类型的cell。
2.单例模式
苹果系统中本身就提供了许多单例类,比如说UIApplication(应用程序实例)、NSNotificationCenter(消息中心)、NSFileManager(文件管理)、NSUserDefaults(应用程序设置)等。
自己实现的单例,注意我们要实现的单例应该是一个完整意义上的单例,就是无论我们用alloc init方法还是copy还是用类方法声明的对象都是一个实例,并且是线程安全的,也就是多个线程同时访问的时候只有一个实例对象。
要想实现完全意义上的单例,我们需要让类遵守NSCopying协议,并且重写copyWithZone方法。
如果我们只是重写了share方法,那么虽然用share方法初始化的时候是一个单例,但是如果用alloc init方法初始化的时候又会生成一个新的对象,就不是单例了。
⚠️:这个时候,我们需要从根本入手!重写allocWithZone方法,因为其他方法根本上都是调用这个方法。
正确的做法:
staticTRDataManager *_dataManager =nil;
+ (instancetype)allocWithZone:(struct_NSZone *)zone {
static dispatch_once_t once;
dispatch_once(&once , ^{//第一个参数是一个dispatch_once_t类型的对象,相当于一个标识,同一个标识对应的dispatch_once方法只执行一次,所以这个对象应该声明成静态变量,整个程序运行过程中都是一个对象。
_dataManager = [super allocWithZone:zone];
});
return_dataManager;
}
+ (instancetype)sharedDataManager {
if(nil== _dataManager) {
_dataManager = [[TRDataManager alloc]init];
}
return_dataManager
;}
- (id)copyWithZone:(NSZone*)zone {return_dataManager; }
3.观察者模式
NSNotification和KVO都是观察者模式
网友评论