先开个小头,明天写出来,不逼着自己是不会干活的。
题外话:
首先,设计模式是什么,为什么要用设计模式,设计模式用来做什么?
设计模式是什么?
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. It is a description or template for how to solve a problem that can be used in many different situations. Patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.
对于一些经常出现的具有相似特征的问题,设计一个模式,来解决问题,这个模式具有可移植性,对于不同的问题有高度的抽象解决方法。
为什么用设计模式?
程序之美在与简洁,优雅,易扩展,易维护,可复用,封闭性与开放性兼具。利用设计模式可以达到这些目的。
设计模式用来做什么?
当我们的问题可以抽象成用某个模式,可以利用现有的设计模式来组织我们的代码。
常见的设计模式有:单例模式,委托模式,工厂设计模式,协议等等。
进入正题:
简单工厂模式
专门定义一个类负责创建其他类的实例,被创建的类通常具有共同的父类。
简单工厂模式的UML图
简单工厂模式的角色:
工厂,接受客户端的请求,通过请求负责创建相应的产品对象。
抽象产品,工厂模式所创建对象的父类或者共同拥有的接口。可以是抽象类或接口。
具体产品,工厂模式所创建的对象都是它的实例。
简单工厂模式的主要实现
+(Product *)createProductWithType:(ProductType)type {
switch(type){
case ProductTypeOne:
return[[ProductOne alloc]init];
break;
case ProductTypeTwo:
return[[ProductTwo alloc]init];
break;
case ProductTypeThree:
return[[ProductThree alloc]init];
break;
default:
break;
}
return nil;
}
简单工厂模式的主要缺点:
简单工厂模式不仅对扩展开放,而且对修改也开放,所以违反了“开放-关闭原则”。说人话:当需要扩展一个产品时,不仅需要新建一个产品类,同时还要修改工厂方法。另外,所有产品对象创建的逻辑都被集中到了工厂类中,并不优雅。
工厂方法
和简单工厂方法相比,工厂方法的改进:将工厂类也抽象为了抽象工厂类和工厂子类,外界调用更加灵活,这也是对多态的一种体现。具体产品的生成分布到具体工厂中实现。
具体产品继承抽象产品,具体工厂继承抽象工厂。
//抽象产品
@interfaceProduct:NSObject
@end
@implementationProduct
@end
//具体产品1
@interfaceProductOne:Product
@end
@implementationProductOne
@end
//具体产品2
@interfaceProductTwo:Product
@end
@implementationProductTwo
@end
//抽象工厂
@interfaceFactory:NSObject
+(Product*)createProduct;
@end
@implementationFactory
+(Product*)createProduct
{
return [[Product alloc]init];
//如果Product是抽象的,那么这里可以返回nil
}
@end
//具体产品1的具体工厂
@interfaceProductOneFactory:Factory
+(Product*)createProduct;
@end
@implementationProductOneFactory
+(Product*)createProduct
{
return[[ProductOne alloc]init];
}@end
//具体产品2的具体工厂
@interfaceProductTwoFactory:Factory
+(Product*)createProduct;
@end
@implementationProductTwoFactory
+(Product*)createProduct
{
return[[ProductTwo alloc]init];
}
@end
//客户端调用
Product*p=[ProductOneFactory createProduct];
NSLog(@"%@",p);
Product*p2=[ProductTwoFactory createProduct];
NSLog(@"%@",p2);
优点
工厂方法模式的的优点在于更大的灵活性,增加或删除某个产品都不会对其他地方造成影响,更佳符合开放封闭原则。
而且对抽象的使用更佳深入,将工厂类也抽象为了抽象工厂类和工厂子类,外界调用更加灵活,这也是对多态的一种体现。
缺点
工厂方法模式的缺点也是非常显而易见的,工厂方法模式中新增一个抽象子类,意味着工厂子类要跟着成对增加(OC中要x4),这样会造成生成过多的类,工厂方法模式的复杂度也会随之增加。
抽象工厂模式
抽象工厂模式和工厂方法模式很相似,但是抽象工厂模式将抽象发挥的更加极致,是三种工厂模式中最抽象的一种设计模式
抽象工厂模式中定义了抽象工厂类,抽象工厂类中定义了每个系列的抽象子类创建所需的方法,这些方法对应着不同类型的抽象子类实例化过程。每个工厂子类都对应着一个系列,工厂子类通过重写这些方法来实例化当前系列的抽象子类。
抽象工厂模式与工厂方法模式
两者都用于相同的目的:创建对象而不让客户端知道返回了什么确切的具体对象。
在工厂方法模式中,工厂子类负责抽象子类的实例化,每个工厂子类对应着一个抽象子类,且具有唯一性。而在抽象工厂模式中,一个工厂子类代表一个系列,工厂子类根据当前系列对不同类型的抽象子类进行创建。工厂方法模式中工厂子类对应的是一个类型的抽象子类,抽象工厂模式对应的是一个系列的抽象子类。
简单说:工厂方法模式是针对单个类型的抽象类,而抽象工厂模式是针对具有相同结构的一系列类型的抽象类。
//抽象工厂
@interfaceBrandingFactory:NSObject
+(BrandingFactory*)factory;
-(Hatchback*)createHatchback;
-(SUV*)createSUV;
@end
@implementationBrandingFactory
+(BrandingFactory*)factory
{
if([[self class]isSubclassOfClass:[ToyotaBrandingFactory class]]){
return[[ToyotaBrandingFactory alloc]init];
}else if([[self class]isSubclassOfClass:[FordBrandingFactory class]]){
return[[FordBranding Factory alloc]init];
}else
{
return nil;
}
}
-(Hatchback*)createHatchback
{
return nil;
}
-(SUV*)createSUV
{
return nil;
}
@end
// 具体工厂
@interfaceFordBrandingFactory:BrandingFactory
@end
@implementationFordBrandingFactory
-(Hatchback*)createHatchback
{
FordHatchback*hatchback=[[FordHatchback alloc]init];
return hatchback;
}
-(SUV*)createSUV
{FordSUV *suv=[[FordSUValloc]init];
return suv;
}
@end
@interfaceToyotaBrandingFactory:BrandingFactory
@end
@implementationToyotaBrandingFactory
-(Hatchback*)createHatchback
{
ToyotaHatchback*hatchback=[[ToyotaHatchback alloc]init];
return hatchback;
}
-(SUV*)createSUV
{
ToyotaSUV*suv=[[ToyotaSUValloc]init];returnsuv;
}
@end
//抽象产品
@interfaceHatchback:NSObject
@end
@implementation Hatchback
@end
@interfaceSUV:NSObject
@end
@implementation SUV
@end
//具体产品
@interfaceFordHatchback:Hatchback
@end
@implementationFordHatchback
@end
@interfaceToyotaHatchback:Hatchback
@end
@implementationToyotaHatchback
@end
@interfaceFordSUV:SUV
@end
@implementationFordSUV
@end
@interfaceToyotaSUV:SUV
@end
@implementationToyotaSUV
@end
Cocoa中的抽象工厂模式
创建NSNumber实例的方式完全符合抽象工厂模式。
创建Cocoa对象有两种方式:使用先alloc后init的方法,或者使用类中的+ className...方法。在Cocoa的基础框架中,NSNumber类有很多类方法用于创建各种类型的NSNumber对象。
NSNumber*boolNumber=[NSNumbernumberWithBool:YES];NSNumber*charNumber=[NSNumbernumberWithChar:'a'];NSNumber*intNumber=[NSNumbernumberWithInteger:2];
每个返回的对象属于代表最初输入值的不同私有子类。打印如下:
2016-09-0810:30:28.415OCDemo[1164:29635]__NSCFBoolean2016-09-0810:30:28.416OCDemo[1164:29635]__NSCFNumber2016-09-0810:30:28.416OCDemo[1164:29635]__NSCFNumber
接受不同类型的参数并返回NSNumber实例的类方法是类工厂方法。NSNumber是抽象工厂实现的一个例子。基础框架中抽象工厂的此种特点被称为“类簇”(Class Cluster)。
类簇是基础框架中一种常见的设计模式,基于抽象工厂模式的思想。它将若干相关的私有具体工厂子类集合到一个工友的抽象超类指下。例如,“数”包含了各种数值类型的完整集合,如字符、整数、浮点数和双精度输。这些数值类型是”数“的字集。所以NSNumber自然成为这些数子类型的超类型(super-type)。NSNumber有一系列共有API,定义了各种类型的数所共有的行为。客户端在使用时无需知道NSNumber实例的具体类型。
类簇是抽象工厂的一种形式。比如,NSNumber本身是一个高度抽象的工厂,而NSCFBoolean和NSCFNumber是具体的工厂子类。子类是具体工厂,因为他们重载了NSNumber中声明的公有工厂方法以生产产品。例如,intValue和boolValue根据实际NSNumber对象的内部值返回一个值,虽说值的数据类型可能不同。从这些工厂方法返回的实际值就是抽象工厂模式的最初定义中所说的“产品”。
创建抽象产品的工厂方法与创建抽象工厂的工厂方法之间有个不同点。显然,像intValue和boolValue这样的工厂方法,应在具体工厂(NSCFBoolean和NSCFNumber)中重载以返回实际值(产品)。其他像numberWithBool:和numberWithInteger:这样的工厂方法并不是为了返回产品,而是为了返回能返回产品的工厂,因此它们不应该在具体工厂子类中重载。
其他时限为类簇的基础类有NSData、NSArray、NSDictionary、NSString。
工厂模式总结
在这三种设计模式中都有一个共同的特点,就是继承自抽象类的抽象子类或工厂子类,都必须对抽象类定义的方法给出对应的实现(可以相同,也可以不同),这种模式才叫做工厂模式。工厂模式的核心就是抽象和多态,抽象子类继承自抽象类,对抽象类中定义的方法和属性给出不同的实现方式,通过多态的方式进行方法实现和调用,构成了工厂模式的核心。
在工厂类中对“开放-封闭原则”有着完美的体现,对扩展的开放以及对修改的封闭。例如最抽象的抽象工厂模式,抽象工厂模式中增加新的系列,直接扩展一个工厂子类及对应的抽象子类,对整个模式框架不会带来其他影响。如果增加一个新的类型,创建新的类型对应的类,并对整个抽象工厂类及其子类进行方法扩展。
在外界使用抽象子类的功能时,不需要知道任何关于抽象子类的特征,抽象子类也不会出现在外界,外界只需要和抽象类打交道就可以。工厂模式将抽象子类的创建和实现分离,具体的创建操作由工厂类来进行,抽象子类只需要关注业务即可,外界不需要知道抽象子类实例化的过程。这种方式非常灵活并易于扩展,而且在大型项目中尤为明显,可以很好的避免代码量过多的问题。
大部分摘自:http://ibloodline.com/articles/2016/09/06/factory.html