设计模式之工厂模式(Factory模式)
在面向对象系统设计中经常遇到以下两类问题:
1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。这里很容易出现的一个问题n多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就编写诸如new ×××;的代码。这里带来两个问题1)客户程序员必须知道实际子类的名称(当系统复杂后,命名将是一个很不好处理的问题,为了处理可能的名字冲突,有的命名可能并不是具有很好的可读性和可记忆性,就姑且不论不同程序员千奇百怪的个人偏好了。),2)程序的扩展性和维护变得越来越困难。
2)还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思为:假设我们在类A中要使用到类B,B是一个抽象父类,在A中并不知道具体要实例化那一个B的子类,但是在类A的子类D中是可以知道的。在A中我们没有办法直接使用类似于new ×××的语句,因为根本就不知道×××是什么。
以上两个问题也就引出了Factory模式的两个最重要的功能:
1)定义创建对象的接口,封装了对象的创建;
2)使得具体化类的工作延迟到了子类中。
模式选择
我们通常使用Factory模式来解决上面给出的两个问题。在第一个问题中,我们经常就是声明一个创建对象的接口,并封装了对象的创建过程。Factory这里类似于一个真正意义上的工厂(生产对象)。在第二个问题中,我们需要提供一个对象创建对象的接口,并在子类中提供其具体实现(因为只有在子类中可以决定到底实例化哪一个类)。
第一中情况简单工厂模式的Factory的结构示意图为:
图1:Factory模式结构示意图1
图1所以的Factory模式经常在系统开发中用到,但是这并不是Factory模式的最大威力所在(因为这可以通过其他方式解决这个问题)。Factory模式不单是提供了创建对象的接口,其最重要的是延迟了子类的实例化(第二个问题),以下是这种情况的一个Factory,工厂方法模式的结构示意图:
图2:工厂方法模式
图2中关键中Factory模式的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现:Factory中只是提供了对象创建的接口,其实现将放在Factory的子类ConcreteFactory中进行。这是图2和图1的区别所在。
下面是工厂方法模式的C++实现:
1 //Product.h
2 #ifndef _PRODUCT_H_
3 #define _PRODUCT_H_
4 class Product
5 {
6 public:
7 virtual ~Product() = 0;
8 protected:
9 Product();
10 private:
11 };
12 class ConcreteProduct:public Product
13 {
14 public:
15 ~ConcreteProduct();
16 ConcreteProduct();
17 protected:
18 private:
19 };
20 #endif //~_PRODUCT_H_
1 //Product.cpp
2 #include "Product.h"
3 #include <iostream>
4 using namespace std;
5 Product::Product()
6 {
7 }
8 Product::~Product()
9 {
10 }
11 ConcreteProduct::ConcreteProduct()
12 {
13 cout<<"ConcreteProduct...."<<endl;
14 }
15 ConcreteProduct::~ConcreteProduct()
16 {
17 }
1 //Factory.h
2 #ifndef _FACTORY_H_
3 #define _FACTORY_H_
4 class Product;
5 class Factory
6 {
7 public:
8 virtual ~Factory() = 0;
9 virtual Product* CreateProduct() = 0;
10 protected:
11 Factory();
12 private:
13 };
14 class ConcreteFactory:public Factory
15 {
16 public:
17 ~ConcreteFactory();
18 ConcreteFactory();
19 Product* CreateProduct();
20 protected:
21 private:
22 };
23 #endif //~_FACTORY_H_
1 //Factory.cpp
2 #include "Factory.h"
3 #include "Product.h"
4 #include <iostream>
5 using namespace std;
6 Factory::Factory()
7 {
8 }
9 Factory::~Factory()
10 {
11 }
12 ConcreteFactory::ConcreteFactory()
13 {
14 cout<<"ConcreteFactory....."<<endl;
15 }
16 ConcreteFactory::~ConcreteFactory()
17 {
18 }
19 Product* ConcreteFactory::CreateProduct()
20 {
21 return new ConcreteProduct();
22 }
1 //main.cpp
2 #include "Factory.h"
3 #include "Product.h"
4 int main(int argc,char* argv[])
5 {
6 Factory* fac = new ConcreteFactory();
7 Product* p = fac->CreateProduct();
8 return 0;
9 }
示例代码中给出的是Factory模式解决父类中并不知道具体要实例化哪一个具体的子类的问题,至于为创建对象提供接口问题,可以由Factory中附加相应的创建操作例如Create***Product()即可。具体请参加讨论内容。
Factory模式也带来至少以下两个问题: 1)如果为每一个具体的ConcreteProduct类的实例化提供一个函数体,那么我们可能不得不在系统中添加了一个方法来处理这个新建的ConcreteProduct,这样Factory的接口永远就不肯能封闭(Close)。当然我们可以通过创建一个Factory的子类来通过多态实现这一点,但是这也是以新建一个类作为代价的。
2)在实现中我们可以通过参数化工厂方法,即给FactoryMethod()传递一个参数用以决定是创建具体哪一个具体的Product。当然也可以通过模板化避免1)中的子类创建子类,其方法就是将具体Product类作为模板参数,实现起来也很简单。可以看出,Factory模式对于对象的创建给予开发人员提供了很好的实现策略,但是Factory模式仅仅局限于一类类(就是说Product是一类,有一个共同的基类),如果我们要为不同类的类提供一个对象创建的接口,那就要用AbstractFactory了。
AbstactFactory模式(抽象工厂模式)要创建一组相关或者相互依赖的对象。
假设我们要开发一款游戏,当然为了吸引更多的人玩,游戏难度不能太大(让大家都没有信心了,估计游戏也就没有前途了),但是也不能太简单(没有挑战性也不符合玩家的心理)。于是我们就可以采用这样一种处理策略:为游戏设立等级,初级、中级、高级甚至有BT级。假设也是过关的游戏,每个关卡都有一些怪物(monster)守着,玩家要把这些怪物干掉才可以过关。作为开发者,我们就不得不创建怪物的类,然后初级怪物、中级怪物等都继承自怪物类(当然不同种类的则需要另创建类,但是模式相同)。在每个关卡,我们都要创建怪物的实例,例如初级就创建初级怪物(有很多种类)、中级创建中级怪物
AbstractFactory模式典型的结构图为:
C++实现代码如下:
//Product.h
#ifndef _PRODUCT_H_
#define _PRODUCT_H_
class AbstractProductA
{
public:
virtual ~AbstractProductA();
protected:
AbstractProductA();
private:
};
class AbstractProductB
{
public:
virtual ~AbstractProductB();
protected:
AbstractProductB(); private:
};
class ProductA1:public AbstractProductA
{
public:
ProductA1();
~ProductA1();
protected: private:
};
class ProductA2:public AbstractProductA
{
public:
ProductA2();
~ProductA2();
protected: private:
};
class ProductB1:public AbstractProductB
{
public:
ProductB1();
~ProductB1();
protected:
private:
};
class ProductB2:public AbstractProductB
{
public:
ProductB2();
~ProductB2();
protected: private:
};
#endif //~_PRODUCT_H_ECT_H_ //Product.cpp
#include "Product.h"
#include <iostream>
using namespace std;
AbstractProductA::AbstractProductA()
{ }
AbstractProductA::~AbstractProductA()
{ }
AbstractProductB::AbstractProductB()
{
}
AbstractProductB::~AbstractProductB()
{
}
ProductA1::ProductA1()
{
cout<<"ProductA1..."<<endl;
}
ProductA1::~ProductA1()
{
}
ProductA2::ProductA2()
{
cout<<"ProductA2..."<<endl;
}
ProductA2::~ProductA2()
{
}
ProductB1::ProductB1()
{
cout<<"ProductB1..."<<endl;
}
ProductB1::~ProductB1()
{
}
ProductB2::ProductB2()
{
cout<<"ProductB2..."<<endl;
}
ProductB2::~ProductB2()
{
}
1 //AbstractFactory.h
2 #ifndef _ABSTRACTFACTORY_H_
3 #define _ABSTRACTFACTORY_H_
4 class AbstractProductA;
5 class AbstractProductB;
6 class AbstractFactory
7 {
8 public:
9 virtual ~AbstractFactory();
10 virtual AbstractProductA* CreateProductA() = 0;
11 virtual AbstractProductB* CreateProductB() = 0;
12 protected:
13 AbstractFactory();
14 private:
15 };
16 class ConcreteFactory1:public AbstractFactory
17 {
18 public:
19 ConcreteFactory1();
20 ~ConcreteFactory1();
21 AbstractProductA* CreateProductA();
22 AbstractProductB* CreateProductB();
23 protected:
24 private:
25 };
26 class ConcreteFactory2:public AbstractFactory
27 {
28 public:
29 ConcreteFactory2();
30 ~ConcreteFactory2();
31 AbstractProductA* CreateProductA();
32 AbstractProductB* CreateProductB();
33 protected:
34 private:
35 };
36 #endif //~_ABSTRACTFACTORY_H_
37
38
39 //AbstractFactory.cpp
40 #include "AbstractFactory.h"
41 #include "Product.h"
42 #include <iostream>
43 using namespace std;
44 AbstractFactory::AbstractFactory()
45 {
46 }
47 AbstractFactory::~AbstractFactory()
48 {
49 }
50 ConcreteFactory1::ConcreteFactory1()
51 {
52 }
53 ConcreteFactory1::~ConcreteFactory1()
54 {
55 }
56 AbstractProductA* ConcreteFactory1::CreateProductA()
57 {
58 return new ProductA1();
59 }
60 AbstractProductB* ConcreteFactory1::CreateProductB()
61 {
62 return new ProductB1();
63 }
64 ConcreteFactory2::ConcreteFactory2()
65 {
66 }
67 ConcreteFactory2::~ConcreteFactory2()
68 {
69 }
70 AbstractProductA* ConcreteFactory2::CreateProductA()
71 {
72 return new ProductA2();
73 }
74 AbstractProductB* ConcreteFactory2::CreateProductB()
75 {
76 return new ProductB2();
77 }
1 #include "AbstractFactory.h"
2 #include <iostream>
3 using namespace std;
4 int main(int argc,char* argv[])
5 {
6 AbstractFactory* cf1 = new ConcreteFactory1();
7 cf1->CreateProductA();
8 cf1->CreateProductB();
9 AbstractFactory* cf2 = new ConcreteFactory2();
10 cf2->CreateProductA();
11 cf2->CreateProductB();
12 return 0;
13 }
AbstractFactory模式的实现代码很简单,在测试程序中可以看到,当我们要创建一组对象(ProductA1,ProductA2)的时候我们只用维护一个创建对象(ConcreteFactory1),大大简化了维护的成本和工作。
AbstractFactory模式和Factory模式的区别是初学(使用)设计模式时候的一个容易引起困惑的地方。实际上,AbstractFactory模式是为创建一组(有多类)相关或依赖的对象提供创建接口,而Factory模式正如我在相应的文档中分析的是为一类对象提供创建接口或延迟对象的创建到子类中实现。并且可以看到,AbstractFactory模式通常都是使用Factory模式实现(ConcreteFactory1)。
设计模式之工厂模式(Factory模式)的更多相关文章
- 面向对象设计——抽象工厂(Abstract Factory)模式
定义 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类.抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么.这样一来,客户就能从具体的产 ...
- java设计模式,工厂,代理模式等
javaEE设计模式: 工厂模式:主要分为三种模式: 定义:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行. 为什么要使用工厂模式: (1) 解耦 : ...
- 设计模式之工厂方法(FactoryMethod)模式
在五大设计原则的基础上经过GOF(四人组)的总结,得出了23种经典设计模式,其中分为三大类:创建型(5种).结构型(7种).行为型(11种).今天对创建型中的工厂方法(FactoryMethod)模式 ...
- 设计模式学习笔记 1.factory 模式
Factory 模式 用户不关心工厂的具体类型,只知道这是一个工厂就行. 通过工厂的实现推迟到子类里面去来确定工厂的具体类型. 工厂的具体类型来确定生产的具体产品. 同时用户不关心这是一个什么样子的产 ...
- [C#]设计模式-简单工厂-创建型模式
在设计模式当中有三大工厂,分别是 简单工厂.抽象工厂.工厂方法 这三种创建实例的设计模式,这里先从简单工厂将其,从名字就可以看出这是这三种工厂模式当中最为简单的一种实现. 简单工厂一般由以下几个对象组 ...
- 工厂模式/factory模式/创建型模式
工厂模式 普通工厂模式 原本需要new出来的对象,通过一个类的方法去搞定,Factory.build(parameter),类似这种. public interface Sender { public ...
- [C#]设计模式-抽象工厂-创建型模式
介绍了简单工厂与工厂方法之后,现在我们来看一下工厂三兄弟的最后一个 -- 抽象工厂. 那什么是抽象工厂呢? 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相 ...
- Java 工厂模式(一)— 抽象工厂(Abstract Factory)模式
一.抽象工厂模式介绍: 1.什么是抽象工厂模式: 抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态,抽象工厂模式向客户端提供一个接口,使得客户端在不知道具体产品的情类型的情况下,创建 ...
- 设计模式——抽象工厂(Abstract Factory)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类. ——DP UML类图 模式说明 抽象工厂与工厂方法在定义上最明显的区别是“创建一系列相关或相互依赖对象的接口”,由此可以看出抽象工 ...
随机推荐
- if-else和if if的对比
- MeteoInfoLab脚本示例:计算涡度、散度
用U/V分量数据计算涡度和散度,计算涡度的函数是hcurl,计算散度的函数是hdivg,参数都是U, V.脚本程序: f = addfile('D:/Temp/GrADS/model.ctl') u ...
- MySQL数据库规范 (设计规范+设计规范+操作规范)
I 文档定义 1.1 编写目的 为了在软件生命周期内规范数据库相关的需求分析.设计.开发.测试.运维工作,便于不同团队之间的沟通协调,以及在相关规范上达成共识,提升相关环节的工作效率和系统的可维护性. ...
- pytest文档48-切换 base_url 测试环境(pytest-base-url)
前言 当我们自动化代码写完成之后,期望能在不同的环境测试,这时候应该把 base_url 单独拿出来,能通过配置文件和支持命令行参数执行. pytest-base-url 是 pytest 里面提供的 ...
- 源生代码和H5的交互 android:
1: 默认的事情: Android 通过内置的UI控件WebView来加载网页. 网页是用一个网络地址来表示的: 其整个使用方法很简单如下:(android不关心实际的 ...
- rabbitmq 交换机模式一 广播模式 fanout
<?php require_once "./vendor/autoload.php"; use PhpAmqpLib\Connection\AMQPStreamConnect ...
- spring boot:接口站增加api版本号后的安全增强(spring boot 2.3.3)
一,接口站增加api版本号后需要做安全保障? 1,如果有接口需要登录后才能访问的, 需要用spring security增加授权 2,接口站需要增加api版本号的检验,必须是系统中定义的版本号才能访问 ...
- Scala编程 笔记
date: 2019-08-07 11:15:00 updated: 2019-11-25 20:00:00 Scala编程 笔记 1. makeRDD 和 parallelize 生成 RDD de ...
- Spring Boot学习笔记(一)——Eclipse安装STS插件
一.简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式进行配置,从而使开发人员不再需要定义样板化的配 ...
- 《JavaScript高级程序设计》——第二章在HTML使用JavaScript
这章讲的是JavaScript在HTML中的使用,也就是<script>元素的属性.书中详细讲了async.defer.src和type四个<script>的属性. 下面是对第 ...