【iOS开发】类簇--抽象工厂模式在OC中的使用

来源:互联网 发布:初级程序员证书查询 编辑:程序博客网 时间:2024/06/04 23:30

简介

Class Clusters(类簇)是抽象工厂模式在iOS下的一种实现,众多常用类,如NSString、NSArray、NSDictionary以及NSNumber都运作在这一模式下,它是接口简单性和扩展性的权衡体现,在我们完全不知情的情况下,偷偷隐藏了很多具体的实现类,只暴露出简单的接口。

NSArray的类簇
原有的alloc+init拆开写:

<span style="font-family:Microsoft YaHei;">-(void)cluster{    id obj1 = [NSArray alloc];    id obj2 = [NSMutableArray alloc];    id obj3 = [obj1 init];    id obj4 = [obj2 init];    NSLog(@"%@",NSStringFromClass([obj1 class]));    NSLog(@"%@",NSStringFromClass([obj2 class]));    NSLog(@"%@",NSStringFromClass([obj3 class]));    NSLog(@"%@",NSStringFromClass([obj4 class]));    /*    结果:     2016-01-13 20:58:29.455 1fundation框架[2570:230724]  __NSPlaceholderArray     2016-01-13 20:58:29.456 1fundation框架[2570:230724] __NSPlaceholderArray     2016-01-13 20:58:29.457 1fundation框架[2570:230724] __NSArray0     2016-01-13 20:58:29.457 1fundation框架[2570:230724] __NSArrayM     */}</span>

发现+alloc之后并非生成了我们期望的类实例 而是一个__NSPlaceholderArray的中间对象 后面的-init或者-initWithxx等方法调用都是把消息发送给这个中间对象 再由它做工厂 生成真正的对象。

(这里的__NSArrayI和__NSArrayM分别对应immutable和mutable。)


所以 __NSPlaceholderArray必定用某种方式存储了它是由谁alloc出来这个消息,才能判断是创建哪个类型的数组

而可以测试看得 obj1 obj2的地址是一样的。所以,可以猜测 内部实现应该差不多如下所示

<span style="font-family:Microsoft YaHei;">+(id)alloc{if(self == [NSMutableArray class]){return getNSMutableArray();}else if(self == [NSArray class]){return getNSArray();}}-(id)init{    if (self == getNSArray()) {        return [self initNSArray];    }else if(self == getNSMutableArray())    {        return [self initNSMutableArray];    }}</span>


因此以下代码中:

<span style="font-family:Microsoft YaHei;">id obj1 = [NSArray alloc]; id obj2 = [NSArray alloc];id obj3 = [NSMutableArray alloc];id obj4 = [NSMutableArray alloc];</span>


obj1 obj2地址相同 obj3 obj4地址相同。

那么猜测NSDictionary NSSet NSString等是一样的情况。


对NSNumber的猜想

NSNumber可以存储各种类型的数据, Int Float Double。

站在设计者的角度上看,一种方式是把NSNumber作为基类 然后分别实现各自的子类

但是如果子类过多 对于开发者就很麻烦了。

于是 NSNumber中使用类簇的模式,将子类对外封闭,开发者只需要记住一个父类 而实例化相对应的子类。所以可以猜测其内部实现原理:

- (id)initWithBool {     return [[__NSCFBoolean alloc]init]; }  - (id)initWithLong {     return [[__NSCFNumber alloc]init]; } 


对于开发者:iOS开发中的应用

1.表现和行为完全一样 但是数据源不一样

2.cell的类型不一样

3.应用的兼容,iOS6、7的图片资源不同

现在很多应用需要同时兼顾iOS6和iOS7,在表现上需要为不同的系统加载不同的图片资源,最简单粗暴的方法就是各种if/else判断,像这样:
 
  1. if ([[UIDevice currentDevice]systemMajorVersion] < 7) 
  2.     /* iOS 6 and previous versions */ 
  3. else 
  4.     /* iOS 7 and above */ 
 
不够优雅,可以使用类簇的思想来去掉if/else判断,把跟视图具体元素无关的代码放在基类,跟系统版本相关的代码拆成两个子类,然后在各自的类中加载相应的资源。
  1. /* TestView.h */ 
  2. @interface TestView: UIView 
  3.  
  4. /* Common method */ 
  5. - ( void )test; 
  6.  
  7. @end 
  8.  
  9. /* TestView.m */ 
  10. @implementation TestView 
  11.  
  12. + (id)alloc 
  13.     if ([self class]== [TestView class]) 
  14.     { 
  15.         if ([[UIDevice currentDevice] systemMajorVersion] < 7) 
  16.         { 
  17.             return [TestViewIOS6 alloc]; 
  18.         } 
  19.         else 
  20.         { 
  21.             return [TestViewIOS7 alloc]; 
  22.         } 
  23.     } 
  24.     else 
  25.     { 
  26.         return [super alloc]; 
  27.     } 
  28.  
  29. - ( void )test 
  30. {} 
  31.  
  32. @end 
 
这里alloc时并没有返回TestView类,而是根据系统版本返回TestViewIOS6 或 TestViewIOS7。
 
  1. /* TestViewIOS6.m */ 
  2. @implementation TestViewIOS6: TestView 
  3.  
  4. - (void)drawRect: (CGRect)rect 
  5.     /* Custom iOS6 drawing code */ 
  6.  
  7. @end 
  8.  
  9. /* TestViewIOS7.m */ 
  10. @implementation TestViewIOS7 
  11.  
  12. - (void)drawRect: (CGRect)rect 
  13.     /* Custom iOS7 drawing code */ 
  14.  
  15. @end 
0 0
原创粉丝点击