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

简介

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 
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值