简单工厂:
在介绍工厂方法模式之前先说下简单工厂,简单工厂其实并不是一种设计模式,反而更像是一种编程习惯,我们可以用个简单的例子来说明下简单工厂。
假设我们有一个 AnimalStore(宠物店)
,客户需要从我们这边订购 Cat
,在引如简单工厂模式之前我们的代码可能长这样:
class AnimalStore {
func orderAnimal(type: String) -> Animal? {
var animal: Animal?
if type == "Cat " {
animal = Cat()
}else if type == "Dog"{
animal = Dog()
}else {
//.......
}
}
}
let store = AnimalStore()
let cat = store.orderAnimal("Cat")
使用简单工厂之后,我们可以将创建animal
的代码移动animal
工厂中,AnimalStore
仅需要引用一个SimpleAnimalFactory
实例即可:
/// SimpleAnimalFactory
class SimpleAnimalFactory {
func createAnimal(type: String) -> Animal? {
var animal: Animal?
if type == "Dog " {
animal = Dog()
}else if type == "Cat"{
animal = Cat()
}else {
//...
}
return animal
}
}
/// 原先的AnimalStore改造为
class AnimalStore {
var simpleFactory: SimpleAnimalFactory
init(simpleFactory: SimpleAnimalFactory) {
self.simpleFactory = simpleFactory
}
func orderAnimal(type: String) -> Animal? {
let animal = simpleFactory.createAnimal(type: type)
return animal
}
}
let store = AnimalStore()
let cat = store.orderAnimal("Cat")
当我们需要增加动物的种类的时候,就需要对SimpleAnimalFactory
添加代码。
WHAT工厂方法模式:
说完简单工厂,我们来看看传统的工厂方法`
-
传统的工厂方法模式如下图:
在结合上图,我们可以很清晰的知道何为工厂方法模式:
抽象父类(Product)中定义好创建对象的公共接口,交由子类(Product)实现。
Creator
中声明了抽象的工厂方法,每个ConcreteCreator
中实现抽象工厂中定义的工厂方法。生成返回一个对应Product
的对象。每个工厂对应的生产一种产品。
在iOS中无论OC
还是Swift
都没有抽象类的概念,一般我们采用 Protocol
来实现抽象类。同样用上面 AnimalStore
举栗。
// Creator
protocol AnimalFactoryProtocol {
func createAnimal() -> Animal?
}
// ConcreteCreator
class CatFactory: AnimalFactoryProtocol {
func createAnimal() -> Animal? {
return Cat() as Animal
}
}
class DogFactory: AnimalFactoryProtocol {
func createAnimal() -> Animal? {
return Dog() as Animal
}
}
// Product
class Animal {
func eat() {
print("吃")
}
}
/// ConcreteProduct
class Cat: Animal {
override func eat() {
print("猫吃鱼")
}
}
class Dog: Animal {
override func eat() {
print("狗吃肉")
}
}
之后如果还需要购买Cat
和Dog
时我们只需要从具体的实例工厂中获取就好。
let animalFactory = CatFactory()
let cat = animalFactory.createAnimal()
let animalFactory2 = DogFactory()
let dog = animalFactory2.createAnimal()
工厂方法模式:在工厂父类中定义创建对象的公共接口,而子类则负责生成具体的对象。这样做的目的是将类的实例化操作延迟到子类中完成,即通过子类来确定究竟应该实例化哪一个类。
在工厂方法模式中存在四个的角色:
- 抽象父类(Product):是工厂方法模式所创建对象的超类,即对象的共同父类(NSNumber)。
- 具体子类(ConcreteProduct): 具体子类实现了抽象父类的接口,子类的对象一般与具体工厂的方法一一对应。
- 抽象工厂(Creator): 抽象工厂中声明了工厂方法,用于具体工厂实现,返回一个实例。
- 具体工厂(ConcreteCreator): 具体工厂中实现了抽象工厂中定义的工厂方法,返回具体类的实例。
Objective-C
中的最出名的工厂方法模式莫过于NSNumber
Category中的类工厂方法。
@interface NSNumber (NSNumberCreation)
+ (NSNumber *)numberWithChar:(char)value;
+ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
+ (NSNumber *)numberWithShort:(short)value;
+ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
+ (NSNumber *)numberWithInt:(int)value;
+ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
+ (NSNumber *)numberWithLong:(long)value;
+ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
+ (NSNumber *)numberWithLongLong:(long long)value;
+ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
+ (NSNumber *)numberWithFloat:(float)value;
+ (NSNumber *)numberWithDouble:(double)value;
+ (NSNumber *)numberWithBool:(BOOL)value;
+ (NSNumber *)numberWithInteger:(NSInteger)value API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
在NSNumber
的类工厂方法属于工厂方法的变体,苹果用Category方式向开发者隐藏了具体子类实现的细节。这些类工厂方法,只是NSNumber
提供用于生成对象的便捷方法,并不是用来子类重写的。
WHEN工厂方法模式:
- 在编译期的时候无法准确的确定要创建哪个类的对象。
- 开发者想要在运行时由子类来创建对象。
- 我们不需要知道也不关心具体类的类名(如:NSCFBoolean),只要知道所对应的工厂方法(如:
numberWithBool:
)就能通过其子类来指定创建哪个对象。