开发中常用的设计模式

2018-04-15  本文已影响15人  8fe8946fa366

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都是观察者模式

4. 代理模式

上一篇下一篇

猜你喜欢

热点阅读