1. 简单工厂模式
如何理解简单工厂,工厂方法, 抽象工厂三种设计模式?
简单工厂的生活场景,卖早点的小摊贩,他给你提供包子,馒头,地沟油烙的煎饼等,小贩是一个工厂,它生产包子,馒头,地沟油烙的煎饼。该场景对应的UML图如下所示:
图1:简单工厂模式UML图
简单工厂模式的参与者:
工厂(Factory)角色:接受客户端的请求,通过请求负责创建相应的产品对象。
抽象产品(Abstract Product)角色:是工厂模式所创建对象的父类或是共同拥有的接口。可是抽象类或接口。
具体产品(ConcreteProduct)对象:工厂模式所创建的对象都是这个角色的实例。
简单工厂模式的演变:
1.)当系统中只有唯一的产品时,可以省略抽象产品,如图1所示。这样,工厂角色与具体产品可以合并。
简单工厂模式的优缺点:
1.)工厂类含有必要的创建何种产品的逻辑,这样客户端只需要请求需要的产品,而不需要理会产品的实现细节。
2.)工厂类只有一个,它集中了所有产品创建的逻辑,它将是整个系统的瓶颈,同时造成系统难以拓展。
3.)简单工厂模式通常使用静态工厂方法,这使得工厂类无法由子类继承,这使得工厂角色无法形成基于继承的等级结构。
2. 工厂方法模式
工厂方法使用OOP的多态性,将工厂和产品都抽象出一个基类,在基类中定义统一的接口,然后在具体的工厂中创建具体的产品。工厂方法的生活场景,联合利华要生产“夏士莲”和“清扬”两款洗发水,它会建一个生产“夏士莲”的工厂和一个生产“清扬”的工厂。
图2:工厂方法的UML图
工厂方法模式中的参与者:
抽象工厂角色:与应用程序无关,任何在模式中创建对象的工厂必须实现这个接口。
具体工厂角色:实现了抽象工厂接口的具体类,含有与引用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
抽象产品角色:工厂方法所创建产品对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品角色:这个角色实现了抽象产品角色所声名的接口。工厂方法所创建的每个具体产品对象都是某个具体产品角色的实例。
工厂方法的优缺点:
1.)降低了工厂类的内聚,满足了类之间的层次关系,又很好的符合了面向对象设计中的单一职责原则,这样有利于程序的拓展,如图三所示:
图3:工厂方法的拓展UML图
总结:把“共性”提取出来,根据各自的“个性”建立各自的继承共性的实现
3. 抽象工厂设计模式
所谓抽象工厂是指一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象,以创建Unix控件和Windows控件为例说明,我们需要一个抽象工厂下面有两个子工厂,一个叫做UnixFactory,用于生产Unix族控件,一个叫做WinFactory,用于生产Win族控件。抽象工厂与工厂方法的区别是,工厂方法中的具体工厂一般只生产一个或几个控件对象,而抽象工厂中的具体工厂生产的是一族控件对象。如图4所示。
图4:抽象工厂设计模式UML图
抽象工厂中的参与者:
抽象工厂(Abstract Factory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
具体产品(Concrete Product)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。
抽象工厂的使用场景:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
- 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
- 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
抽象工厂模式与工厂方法模式的区别
工厂方法模式:每个抽象产品派生多个具体产品类,每个抽象工厂类派生多个具体工厂类,每个具体工厂类负责一个具体产品的实例创建;
抽象工厂模式:每个抽象产品派生多个具体产品类,每个抽象工厂派生多个具体工厂类,每个具体工厂负责多个(一系列)具体产品的实例创建。
//在UIKit框架下,我们用工厂方法和抽象工厂两种设计模式分别实现了两份Demo, 不理解两种设计模式该如何实现的朋友可以到这里下载: 刷不出来,以后补上!
1. 主要区别
抽象工厂 |
工厂方法 |
通过对像组合创建产品 | 通过类继承来创建产品 |
生成一系列产品(eg:生成某类view,button,或者其他) |
生成某一种产品(eg:生成某类view) |
必须修改父类接口,才能生成新的产品 | 子类化创建者并重载工厂方法 以创建新产品 |
2. 具体的分析(以下代码引用书上面的例子)
2.1 工厂方法
显然,下面的例子中PaperCanvasView和ClothCanvasView继承自CanvasView,通过重载CanvasView的工厂方法而生成了新的一种产品。
- @interface CanvasViewGenerator : NSObject
- @implementation PaperCanvasViewGenerator
- - (CanvasView *) canvasViewWithFrame:(CGRect) aFrame {
- return [[[PaperCanvasView alloc] initWithFrame:aFrame] autorelease];
- }
- @implementation ClothCanvasViewGenerator
- - (CanvasView *) canvasViewWithFrame:(CGRect) aFrame {
- return [[[ClothCanvasView alloc] initWithFrame:aFrame] autorelease];
- }
工厂方法的应用场景:
1. 编译时无法准备预期要生成的创建的对象的类
2. 类需要由子类决定运行时生成什么。
2.2 抽象工厂
一样的先上代码:
- @interface BrandingFactory : NSObject
- + (BrandingFactory *) factory;
- - (UIView *) brandedView;
- - (UIButton *) brandedMainButton;
- - (UIToolbar *) brandedToolbar;
- @implementation BrandingFactory
- + (BrandingFactory *) factory {
- #if defined (USE_ACME)
- return [[[AcmeBrandingFactory alloc] init] autorelease];
- #elif defined (USE_SIERRA)
- return [[[SierraBrandingFactory alloc] init] autorelease];
- #else
- return nil;
- #endif
- }
- - (UIView *) brandedView {
- return nil;
- }
- - (UIButton *) brandedMainButton {
- return nil;
- }
- - (UIToolbar *) brandedToolbar{
- return nil;
- }
显然这里有两个工厂,生成了一系列的产品如 UIView, UIButton, UIToolbar。而这两个工厂又是由BrandingFactory产生的。子类需要重写这三个方法才能生成新的产品。
抽象工厂的应用场景:
抽象工厂提供一个固定的接口,用于创建一系列由关联或者相依存的对象,而不必指定其具体类或其创建细节。
(引用书中的例子:虽然每家店的比萨饼不一样,同一家比萨饼也有多种口味,但是制作的基本步骤确实一样的。对于我们,将比萨饼看成一种食物,厨师就像是生成比萨饼的工厂。但实际的产品的细节会有所不同。所以,厨师们都知道制作比萨饼的“通用的”或“抽象”的基本知识,但他们有自己的“实现”或“具体”,因此产生的比萨饼不一样)