NSNumber中的设计模式
在NSNumber中用到了常用的一种设计模式-抽象工厂模式, 这也是NSNumber能很好的将c语言中各种基本数据类型封装成对象的原因之一. 那么什么是抽象工厂模式呢? 抽象工厂模式又在何时使用以及如何使用. 下面我来谈谈我读完书后对它的理解,
什么是抽象工厂模式
标准定义
抽象工厂模式的标准定义是提供一系列创建相关或或相互依赖对象的接口, 而无需指定他们具体的类.
举例1
举个我们常见的例子来说比如披萨. 披萨的种类特别多比如意大利披萨, 芝加哥披萨等等. 不同的披萨里面的肉, 酱汁都会有所不同, 但是他们都具有共同特点比如面包, 酱, 奶酪. 而我们就把这些共同特点抽象成一种食物类型披萨. 它定义了披萨基本特征即共有特点, 制作披萨饼的师傅都可以称作“抽象”的披萨饼厨师. 而具体制作意大利披萨,芝加哥披萨的厨师则可以看作“具体”的披萨饼厨师, 这些厨师能做出特定类型的一种披萨, 我们消费者只需要点特定一种披萨但是不需要知道具体知道每种披萨是怎么做出来的,
上述例子中披萨厨师就可以视作抽象工厂, 而意大利披萨,芝加哥披萨的厨师可以看作具体的工厂, 厨师们知道披萨的基本特征, 制作披萨时都会按照基本的制作披萨的规则, 但是不同披萨厨师的做法又会有所不同, 他们以自己特定风味生厂出特定一种披萨饼.
举例2
再看一个更具体的例子就能很好理解抽象工厂.如下图所示:
我们这里现在有一个抽象的品牌工厂类BrandingFactory, 然后他有两个具体工厂类SlerraBrandingFactory和AcmeBrandingFactory, 他们负责创建不同品牌的视图组合(View, Button, Toobar), 具体工厂类在创建具体产品时会一些有不同的做法(比如会加入各自的品牌标志). 然而调用者只知道 BrandingFactory、UIView、UIButton、 UIToobar这四个类, 而不知道内部实现细节的具体类. 使用者只需要使用BrandingFactory的factory方法创建一个抽象工厂类的实例, 然后通过一些参数告诉抽象工厂你想要生厂哪种产品. 抽象工厂就会让具体工厂生产出一种品牌的视图组合, 然后调用工厂方法就能获得视图View、Button或者Toobar.
具体使用为下列代码:
BrandingFactory *slerraBrandingFactory = [BrandingFactory factory];
/**这里还需要额外操作告诉抽象工厂你想要生厂哪种产品*/
UIView *view = [slerraBrandingFactory brandView];
抽象工厂模式的好处
- 抽象工厂模式可以将许多相关、相类似的类聚合到抽象父类中, 我们只需要调用抽象工厂的类方法获得抽象类的对象,使用抽象类定义的公有方法, 但是却不知道对象具体是哪种类, 具体方法如何实现的, 保证了良好的封装性.
- 增加新的具体工厂和产品族很简单.
抽象工厂模式的缺点
- 增加新的产品等级需要同时修改抽象工厂的代码和具体工厂的方法, 比如上述例子中产品若需要再增加一种视图TextView, 那么抽象工厂应该增加brandedTextView方法, 每个具体工厂也需要增加此方法并且添加它的实现.
NSNumber中如何使用抽象工厂模式
NSNumber类中为我们提供了很多类方法用于创建各种类型的NSNumber对象. 像下面这样
NSNumber *boolNumber = [NSNumber numberWithBool:YES];
NSNumber *charNumber = [NSNumber numberWithChar:'a'];
NSNumber *intNumber = [NSNumber numberWithInt:1];
NSNumber *doubleNumber = [NSNumber numberWithDouble:1.0];
不同的工厂方法实际会创造出属于不同具体工厂类的对象, 我们可以使用NSLog打印一下每个对象所属类的描述.
NSLog(@"%@", [[boolNumber class]description]);
NSLog(@"%@", [[charNumber class]description]);
NSLog(@"%@", [[intNumber class]description]);
NSLog(@"%@", [[doubleNumber class]description]);
打印结果如下:
从打印结果可以看出来对象所属的类确实不是都相同的. NSCFBoolean和NSCFNumber就是NSNumber的具体子类. 上述四个对象就是具体子类的实例, 但是它们都支持NSNumber的公有接口.
虽然他们属于不同的具体子类, 但是其行为都有抽象超类NSNumber定义. 我们尝试执行下面的代码段看看.
NSLog(@"%d", [boolNumber intValue]);
NSLog(@"%@", [charNumber boolValue] ? @"YES": @"NO");
控制台输出:
boolNumber内部保持了布尔值YES, 但仍实现了公有intValue方法, 返回反映其内部布尔值的合适整形值, 同样charNumber也实现了公有boolValue方法, 返回反映其内部字符值‘a’的合适布尔值.
总结
接受不同类型的参数值并返回NSNumber实例的使用了类工厂方法. 使用numberWithBool就创建NSCFBoolean工厂的实例, 使用numberWithInt就创建NSCFNumber的实例, 然后他们都实现了NSNumber抽象工厂类对象的的公有方法比如intValue、boolValue. 然而我们调用时并不知道它到底实际属于NSCFBoolean还是NSCFNumber, 只需要把它当作NSNumber的实例, 并且调用它提供的公有方法.