精讲设计模式——工厂模式(Factory模式)

本文探讨了面向对象系统设计中遇到的两类问题:一是如何提高内聚性和松耦合,二是父类无法确定实例化哪个具体子类。工厂模式通过提供创建对象的接口和延迟子类实例化来解决这些问题。示例代码展示了工厂模式的实现,包括产品类和工厂类的定义,以及在实际项目中的应用和潜在问题。工厂模式在系统可读性和维护性方面具有优势,但也可能导致接口封闭性不足和增加类的数量。
摘要由CSDN通过智能技术生成

1、问题

        在面向对象系统设计中经常可以遇到以下的两类问题:

         1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共 接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子 类实现,达到了多态的目的。这里很容易出现的一个问题 n 多的子类继承自抽象基类,我们 不得不在每次要用到子类的地方就编写诸如 new ×××;的代码。这里带来两个问题 1)客 户程序员必须知道实际子类的名称(当系统复杂后,命名将是一个很不好处理的问题,为了 处理可能的名字冲突,有的命名可能并不是具有很好的可读性和可记忆性,就姑且不论不同 程序员千奇百怪的个人偏好了。),2)程序的扩展性和维护变得越来越困难。

        2)还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思 为:假设我们在类 A 中要使用到类 B,B 是一个抽象父类,在 A 中并不知道具体要实例化 那一个 B 的子类,但是在类 A 的子类 D 中是可以知道的。在 A 中我们没有办法直接使用类 似于 new ×××的语句,因为根本就不知道×××是什么。 以上两个问题也就引出了 Factory 模式的两个最重要的功能:

        1)定义创建对象的接口,封装了对象的创建;

        2)使得具体化类的工作延迟到了子类中。

2、模式选择

        我们通常使用 Factory 模式来解决上面给出的两个问题。在第一个问题中,我们经常就 是声明一个创建对象的接口,并封装了对象的创建过程。Factory 这里类似于一个真正意义 上的工厂(生产对象)。在第二个问题中,我们需要提供一个对象创建对象的接口,并在子 类中提供其具体实现(因为只有在子类中可以决定到底实例化哪一个类)。

         第一中情况的 Factory 的结构示意图为:

 图1

        上图所示的 Factory 模式经常在系统开发中用到,但是这并不是 Factory 模式的最大威 力所在(因为这可以通过其他方式解决这个问题)。Factory 模式不单是提供了创建对象的接 口,其最重要的是延迟了子类的实例化(第二个问题),以下是这种情况的一个 Factory 的 结构示意图

图2 

        上图中关键中 Factory 模式的应用并不是只是为了封装对象的创建,而是要把对象的创 建放到子类中实现:Factory 中只是提供了对象创建的接口,其实现将放在 Factory 的子类 ConcreteFactory 中进行。这是图 2 和图 1 的区别。

3、实现

        完整代码示例(code) 

Factory 模式的实现比较简单,这里为了方便初学者的学习和参考,将给出完整的实现代码(所有代码采用 C++实现,并在 VC 6.0 下测试运行)

//代码片断 1:Product.h 

//Product.h 
#ifndef _PRODUCT_H_ 
#define _PRODUCT_H_ 
class Product 
{ 
public: 
virtual ~Product() = 0; 
 
protected: 
 Product(); 
private: 
}; 
class ConcreteProduct:public Product 
{ 
public: 
 ~ConcreteProduct(); 
 ConcreteProduct(); 
 
protected: 
private: 
}; 
#endif //~_PRODUCT_H_
//代码片断 2:Product.cpp 

//Product.cpp 
#include "Product.h" 
#include <iostream> 
using namespace std; 
Product::Product() 
{ 
 
} 
Product::~Product() 
{ 
} 
ConcreteProduct::ConcreteProduct() 
{ 
 cout<<"ConcreteProduct...."<<endl; 
} 
ConcreteProduct::~ConcreteProduct() 
{ 
}
//代码片断 3:Factory.h 

//Factory.h 
#ifndef _FACTORY_H_ 
#define _FACTORY_H_ 
class Product; 
class Factory 
{ 
public: 
virtual ~Factory() = 0;
virtual Product* CreateProduct() = 0; 
protected: 
 Factory(); 
private: 
}; 
class ConcreteFactory:public Factory
{ 
public: 
 ~ConcreteFactory(); 
 ConcreteFactory(); 
 Product* CreateProduct(); 
protected: 
private: 
}; 
#endif //~_FACTORY_H_
//代码片断 4: Factory.cpp 

//Factory.cpp 
#include "Factory.h" 
#include "Product.h" 
#include <iostream> 
using namespace std; 
Factory::Factory() 
{ 
}
Factory::~Factory() 
{ 
}
ConcreteFactory::ConcreteFactory() 
{ 
 cout<<"ConcreteFactory....."<<endl; 
} 
ConcreteFactory::~ConcreteFactory() 
{ 
} 
Product* ConcreteFactory::CreateProduct() 
{ 
return new ConcreteProduct(); 
}
//代码片断 5:main.cpp 

//main.cpp 
#include "Factory.h" 
#include "Product.h"

#include <iostream> 
using namespace std; 

int main(int argc,char* argv[])
{ 
    Factory* fac = new ConcreteFactory(); 
    Product* p = fac->CreateProduct(); 
    return 0;
} 

代码说明

        示例代码中给出的是 Factory 模式解决父类中并不知道具体要实例化哪一个具体的子类 的问题,至于为创建对象提供接口问题,可以由 Factory 中附加相应的创建操作例如 Create***Product()即可。具体请参加讨论内容。

4、讨论

        Factory 模式在实际开发中应用非常广泛,面向对象的系统经常面临着对象创建问题: 要创建的类实在是太多了。而 Factory 提供的创建对象的接口封装(第一个功能),以及其 将类的实例化推迟到子类(第二个功能)都部分地解决了实际问题。一个简单的例子就是笔 者开开发 VisualCMCS 系统的语义分析过程中,由于要为文法中的每个非终结符构造一个类 处理,因此这个过程中对象的创建非常多,采用 Factory 模式后系统可读性性和维护都变得 elegant 许多。

        Factory 模式也带来至少以下两个问题

        1)如果为每一个具体的 ConcreteProduct 类的实例化提供一个函数体,那么我们可能不 得不在系统中添加了一个方法来处理这个新建的 ConcreteProduct,这样 Factory 的接口永远 就不肯能封闭(Close)。当然我们可以通过创建一个 Factory 的子类来通过多态实现这一点, 但是这也是以新建一个类作为代价的。

        2)在实现中我们可以通过参数化工厂方法,即给 FactoryMethod()传递一个参数用以 决定是创建具体哪一个具体的 Product(实际上笔者在 VisualCMCS 中也正是这样做的)。当 然也可以通过模板化避免 1)中的子类创建子类,其方法就是将具体 Product 类作为模板参 数,实现起来也很简单。

         可以看出,Factory 模式对于对象的创建给予开发人员提供了很好的实现策略,但是 Factory 模式仅仅局限于一类类(就是说 Product 是一类,有一个共同的基类),如果我们要 为不同类的类提供一个对象创建的接口,那就要用 AbstractFactory 了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值