哲学上说“是什么,为什么,怎么用”是认识问题的逻辑思维过程.
本文将以厂长工厂造车为例子讲述这三种设计模式。
简单工厂模式
是什么
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
简单工厂模式主要包含三部分:
工厂类角色:本模式核心,含有商业逻辑和判断逻辑,根据逻辑不同,生产具体的工厂产品。
抽象产品角色:定义了工厂方法创建的对象的接口。由接口或者抽象类来实现。
具体产品角色:工厂类所创建的对象就是此实例。由具体类实现。
怎么用
第一年:生意来了,老板就一个厂要造benz,audi的。
#import "CarSampleFactory.h"
@implementation CarSampleFactory
// 抽象产品就是具体产品的接口,直接用一句话代替了
-(void)createCarWithName:(NSString *)name {
NSArray *car = @[@"Benz", @"BMW", @"Audi"];
NSUInteger index = [car indexOfObject:name];
switch (index) {
case 0:
NSLog(@"生产了Benz具体产品(alloc你需要的类)");
break;
case 1:
NSLog(@"生产了Audi具体产品");
break;
default:
break;
}
}
@end
为什么
- 优点
工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建的。所以也称之‘上帝类’。 - 缺点
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中。每增加一种品牌的车子,都要修改逻辑判断处代码。不符合开闭原则,。
这些缺点在工厂方法模式中得到了一定的克服。
工厂模式
是什么
工厂方法模式是一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。
- 抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口或者继承。
- 具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
- 抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
- 具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。(benz车)
怎么用
第二年:生意越做越大,Audi啊来了,厂子忙不过了。聪明的厂长又开了三个厂子,并且叫了一个管理者(抽象工厂)来管理这些工厂。
#import "ViewController.h"
// 工厂方法
// 第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。
BMWFactory *BMWF = [[BMWFactory alloc] init];
[BMWF CreateCarBMW];
// 第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的(类似多态)
CarAbstractFactory *caf = [[BMWFactory alloc] init];
[caf CreateCarFactoy];
caf = [[BenzFactory alloc] init];
[caf CreateCarFactoy];
#import "CarAbstractFactory.h"
@implementation CarAbstractFactory
//抽象工厂
-(void)CreateCarFactoye{
}
@end
#import "BenzFactory.h"
//具体工厂
@implementation BenzFactory
-(void)CreateCarFactoy{
[self CreateCarBenz];
}
- (void)CreateCarBenz{
//具体产品
NSLog(@"工厂方法生产了Benz具体产品(alloc你需要的类)");
}
@end
#import "BMWFactory.h"
@implementation BMWFactory
-(void)CreateCarFactoy{
[self CreateCarBMW];
}
- (void)CreateCarBMW{
NSLog(@"工厂方法生产了BMW具体产品(alloc你需要的类)");
}
@end
#import "AudiFactory.h"
@implementation AudiFactory
-(void)CreateCarFactoy{
[self CreateCarAudi];
}
- (void)CreateCarAudi{
NSLog(@"工厂方法生产了Benz具体产品(alloc你需要的类)");
}
@end
为什么
优点
工厂方法模式是简单工厂模式的衍生,相当于横向扩展。当有新的产品(法拉利汽车),只要新建继承抽象工厂的类就好了。完全符合继承原则。缺点
但是产品种类特别多的时候,就会产生大量的工厂类。所以对于类似的产品我们还是用简单工厂来实现。复杂的业务逻辑可以使用两者结合的模式。开发者依照自身取舍。
可是benz和audi等工厂突然又想生产自己suv,跑车等等,那只能在工厂里写个各种逻辑判断,好吧,又违反了开闭原则,又回到类似简单工厂的弊端。这时候就需要用到抽象工厂模式。
抽象工厂模式
是什么
是工厂方法设计模式的一种扩展。当有多个抽象角色时,使用的一种工厂模式。
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
- 产品等级结构:产品等级结构即产品的继承结构(三种品牌汽车构成了三个不同的产品等级结构)
- 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。比如(suv工厂里生产的三个品牌车型)
怎么用
第三年:audi,benz,bmw告诉厂长,我们这次的订单需要分成suv,business,sport三种类型的车。这时候管理蛮不过来了。所以厂子又请了两个管理。分别管理三个品牌的车子。
// 抽象工厂两种情况同工厂方法上
// method 1
SUVFactory *suvf = [[SUVFactory alloc] init];
[suvf createAudiCar];
// method 2
AbstractFactorys *af = [[SportsFactorys alloc] init];
[af CreateAudiFactoy];
#import <Foundation/Foundation.h>
@interface AbstractFactorys : NSObject
//抽象工厂(三个管理者)
-(void)CreateBenzFactoy;
-(void)CreateBMWFactoy;
-(void)CreateAudiFactoy;
@end
#import "SUVFactory.h"
//具体工厂
@implementation SUVFactory
-(void)createBenzCar{
NSLog(@"抽象工厂方法生产了benzSUV");
}
-(void)createBWMCar{
NSLog(@"抽象工厂方法生产了BWMSUV");
}
-(void)createAudiCar{
NSLog(@"抽象工厂方法生产了AudiSUV");
}
@end
为什么
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率,如使用工厂方法模式,上图所示结构需要提供15个具体工厂,而使用抽象工厂模式只需要提供3个具体工厂。
当增加新的产品族的时候,符合“开闭原则”,只需让产品继承相应的抽象产品,对象的工厂继承抽象工厂即可,而无需修改其他的代码。
当增加产品等级结构的时候,不符合“开闭原则”,如新添加大众,那么在soprt,suv,business三个具体工厂里面都进行修改。当然我们可以配合反射机制来对抽象工厂进行优化。
//根据字符串来创建类
NSClassFromString(<#NSString * _Nonnull aClassName#>)```
----
###总结
简单工厂启示是工厂方法的一种极端实现,工厂方法是抽象方法的一种极端实现。在实际项目中,如果不是项目过大或者功能过于复杂,抽象工厂设计模式一般使用不到。简单工厂模式反而是用的比较频繁。但是这种思想我们还是需要借鉴的。在CoCoa Touch框架中的'类簇'便是基于抽象工厂模式设计。NSNumber就是最好的例子。
NSNumber *boolNumber = [NSNumber numberWithBool:YES];
NSLog(@"%@",[[boolNumber class] description]);
// 输出 __NSCFBoolean
NSLog(@"%d",[boolNumber boolValue]);
//输出1
NSNumber(抽象工厂)->NSCFBoolean(具体工厂子类)-> 重载boolValue工厂方法 ->返回实际产品
这种设计多类型的对象的创建。好的模式应该是变成一种抽象,不暴露创建过程中任何不必要的细节和创建对象的具体类型。
ps:最后厂长去打lol了
都看到最后了还不给个喜欢么……
[demo](https://github.com/Xmanzn/Design-Patterns)