使用情景:
再不确定会有多少个处理操作时应该考虑使用简单工厂模式,如针对同样的接收到的数据,处理的逻辑可能会不同,可能以后还会增加新的操作。
案例:
例如如果实现计算器的功能时,对于同样的输入数据,可能执行加、减、乘、除,甚至其他的功能。因此可以抽象出一个操作的抽象类或是接口,提供一个统一的处理方法(此处为process),然后每种操作创建出一个子类出来。而判断具体使用哪个具体的实现类是在工厂类中进行判断的(将存放操作的变量传递给工厂的生产方法)。工厂类始终返回的是这个抽象类,这样如果对原有功能进行更改或是新添加新的功能,也不会对原来的其他类做修改,只编译修改的那个类或是新的类就可以了。
这样就做到了把耦合降到最低,同时也便于维护。
注意:如果客户提出要再添加一个功能来处理这些数据,实现起来就灰常方便了。
简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。
本文是本人对这三种模式学习后的一个小结以及对他们之间的区别的理解。
简单工厂
简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。
不修改代码的话,是无法扩展的。
工厂方法
工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。
在同一等级结构中,支持增加任意产品。
抽象工厂
抽象工厂是应对产品族概念的。比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。
应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。
小结
★工厂模式中,重要的是工厂类,而不是产品类。产品类可以是多种形式,多层继承或者是单个类都是可以的。但要明确的,工厂模式的接口只会返回一种类型的实例,这是在设计产品类的时候需要注意的,最好是有父类或者共同实现的接口。
★使用工厂模式,返回的实例一定是工厂创建的,而不是从其他对象中获取的。
★工厂模式返回的实例可以不是新创建的,返回由工厂创建好的实例也是可以的。
区别
简单工厂 : 用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)
工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂 :用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
以上三种工厂 方法在等级结构和产品族这两个方向上的支持程度不同。所以要根据情况考虑应该使用哪种方法。
一.简单工厂模式又称静态工厂方法模式(Static Factory Method),它不是Gof 所讲的23种设计模式之一,但是它却是我们在编码过程中经常使用的方法之一。
1.静态工厂方法统一管理对象的创建。
静态工厂方法通过传入的参数判断决定创建哪一个产品的实例,封装了对象的创建,客户端只管消费,实现了对责任(模块)的分割。
2.静态工厂方法推迟了产品的实例化。
通过XML配置文件就能改变具体要创建的产品实例,修改为其它的产品实例,代码不须重新编译。
二.简单工厂模式还是有缺点的,后面的工厂方法模式和抽象工厂模式就是对这些缺点的改善。讲完了这三种模式将会有一个对比。以下以Nokia手机为例,采用简单工厂模式设计的源代码雏形。
- /* Nokia抽象产品 */
- #pragma once
- #include <string>
- #include <iostream>
- class CNokia
- {
- public:
- CNokia(void);
- public:
- virtual ~CNokia(void);
- public:
- virtual bool MakeCall(const std::string & number) const = 0;
- };
- #include "Nokia.h"
- CNokia::CNokia(void)
- {
- }
- CNokia::~CNokia(void)
- {
- }
- #pragma once
- #include "nokia.h"
- class CN96 : public CNokia
- {
- public:
- CN96(void);
- public:
- virtual ~CN96(void);
- public:
- virtual bool MakeCall(const std::string & number) const;
- };
- /* N96型号的Nokia手机产品类 */
- #include "N96.h"
- CN96::CN96(void)
- {
- std::cout << "生产一部N96" << std::endl;
- }
- CN96::~CN96(void)
- {
- }
- bool CN96::MakeCall(const std::string & number) const
- {
- std::cout << "我在用N96,拨打号码是:" << number.c_str() << std::endl;
- return false;
- }
- #pragma once
- #include "nokia.h"
- class CN95 :public CNokia
- {
- public:
- CN95(void);
- public:
- virtual ~CN95(void);
- public:
- virtual bool MakeCall(const std::string & number) const;
- };
- /* N95型号的Nokia手机产品类 */
- #include "N95.h"
- CN95::CN95(void)
- {
- std::cout << "生产一部N95" << std::endl;
- }
- CN95::~CN95(void)
- {
- }
- bool CN95::MakeCall(const std::string & number) const
- {
- std::cout << "我在用N95,拨打号码是:" << number.c_str() << std::endl;
- return false;
- }
- /*N85, N81, ...*/
- /* 工厂类 */
- #pragma once
- #include "N96.h"
- #include "N95.h"
- #include "N85.h"
- #include "N81.h"
- #include <cassert>
- class CNokiaSimpleFactory
- {
- public:
- CNokiaSimpleFactory(void);
- public:
- ~CNokiaSimpleFactory(void);
- public:
- /* 静态工厂方法 */
- static CNokia * CreateNokia(const std::string & model);
- };
- #include "NokiaSimpleFactory.h"
- CNokiaSimpleFactory::CNokiaSimpleFactory(void)
- {
- }
- CNokiaSimpleFactory::~CNokiaSimpleFactory(void)
- {
- }
- CNokia * CNokiaSimpleFactory::CreateNokia(const std::string & model)
- {
- if (model == "N96")
- {
- return new CN96();
- }
- else if (model == "N95")
- {
- return new CN95();
- }
- else if (model == "N85")
- {
- return new CN85();
- }
- else if (model == "N81")
- {
- return new CN81();
- }
- else
- {
- assert(false);
- }
- return NULL;
- }
- /* main方法,可以看做客户端 */
- #include "stdafx.h"
- #include "NokiaSimpleFactory.h"
- int _tmain(int argc, _TCHAR* argv[])
- {
- CNokia * nokia = NULL;
- /*
- modeName 可以从外部XML文件中读取,运行过程中动态的
- 决定该创建哪一种型号的手机
- */
- std::string modeName = "N96";
- nokia = CNokiaSimpleFactory::CreateNokia(modeName);
- nokia->MakeCall("123456789");
- delete nokia;
- nokia = NULL;
- return 0;
- }
-
-
-
工厂方法模式是对简单工厂模式的改进。首先看看简单工厂模式的缺点。
软件是之所以区别于程序,是因为它可以被人们使用,并能间接创造效益。需求是软件开发的核心,忽视用户的需求,软件本身就没有存在的价值。假如Nokia又新开发了一款新手机N99,对于采用简单工厂模式设计的系统,我们的做法是:
1.新增一个CN99类继承自CNokia抽象类,这个符合OCP原则。
注:OCP:Open-Closed Principle开闭原则。OCP关注的是灵活性,改动是通过增加代码进行的,而不是改动现有的代码。对扩展开放,对修改关闭。
2.修改静态工厂方法中的判断逻辑,增加对N99的创建代码。这个明显违背OCP。改进简单工厂模式,我们要做的就是克服2中的缺点。
下面的工厂方法模式,新增一个N96的工厂类,不用修改已有的代码,完全支持OCP原则,而且工厂方法模式也完全遵守里氏替换原则,LSP原则是OCP成为可能的重要原则。
注:Liskov Substitution Principle(里氏代换原则):子类型(subtype)必须能够替换它们的基类型。虽然工厂方法模式是对简单工厂模式缺点的该进,这个缺点就是违背软件设计原则OCP。但是并不是工厂方法模式就优于简单工厂模式,只不过后者更符合常规的软件设计理念。
- /* 抽象工厂类 */
- #pragma once
- #include "Nokia.h"
- class CFactoryMethod
- {
- public:
- CFactoryMethod(void);
- public:
- virtual ~CFactoryMethod(void);
- public:
- virtual CNokia * CreateNokiaMobile(void) = 0;
- };
- #include "FactoryMethod.h"
- CFactoryMethod::CFactoryMethod(void)
- {
- }
- CFactoryMethod::~CFactoryMethod(void)
- {
- }
- /* 生产N99的具体工厂类 */
- #pragma once
- #include "factorymethod.h"
- #include "N96.h"
- class CN96Factory :
- public CFactoryMethod
- {
- public:
- CN96Factory(void);
- public:
- virtual ~CN96Factory(void);
- public:
- virtual CNokia * CreateNokiaMobile(void);
- };
- #include "N96Factory.h"
- CN96Factory::CN96Factory(void)
- {
- }
- CN96Factory::~CN96Factory(void)
- {
- }
- CNokia * CN96Factory::CreateNokiaMobile(void)
- {
- return new CN96();
- }
- /* 客户端通过建立N99工厂生产Nokia手机 */
- #include "stdafx.h"
- #include "N96Factory.h"
- int _tmain(int argc, _TCHAR* argv[])
- {
- CFactoryMethod * factoryMethod = new CN96Factory();
- CNokia * nokia = factoryMethod->CreateNokiaMobile();
- nokia->MakeCall("1234567");
- return 0;
- }
-
-
抽象工厂定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。结构
理解1. AbstractFactory 是抽象工厂类,声明创建产品族的接口。具体工厂创建具体的产品族(Product Family ),可以创建出分属于不同产品等级的一个产品族中的所有对象。ConcreteFactory1 和ConcreteFactory2 分别生产2 个不同产品族。举例:手机工厂生产的产品族中,产品有Linux 系统的手机和Windows 系统的手机。PC 工厂生产的产品族中,产品有Linux 系统的PC 和Windows 系统的PC 。2. AbstractProductA 和AbstractProductB 是产品基类。它们的派生类是同产品等级结构(产品类型)的具的体产品。举例:Linux 的具体产品类型包括Linux 手机版和Linux PC 版,Windows 的具体产品类型包括Windows 手机版和Windows PC 版。产品族和产品等级的关系:
从上图可以看出,4 个具体工厂,每个产品族有3 个不同类型的产品,可以生产具体产品4*3=12 中具体产品。而对于工厂方法模式,生产12 中产品,需要有12 个工厂。3. 调用者(Client )只能看到抽象层次接口。要点1. 抽象工厂应用场景:一个系统要独立于它的产品的创建、组合和表示时。一个系统要由多个产品系列中的一个来配置时。当你要强调一系列相关的产品对象的设计以便进行联合使用时。当你提供一个产品类库,而只想显示它们的接口而不是实现时。2. 新增产品复杂 。抽象工厂增加产品组件时,需要更改所有工厂的接口。如增加产品ProductC ,则工厂基类和具体工厂需要增加接口CreateProductC 。3. 抽象工厂模式与工厂方法模式的区别。a. 重点不同。工厂方法模式强调的是不同的创建者根据自身需求去生产不同的具体产品,重点是生产具体产品;而抽象工厂模式则定位为“在不指定实体类别的前提下,提供了一个可以创建一系列相关或互相依赖之组件的接口”,重点是创建相关组件。b. 抽象工厂提供了的“相关组件”可以看成是具体的产品(如ProductA1 ),抽象工厂模式的“相关组件”可由工厂模式实现。ConcreteFactory1.CreateProuductA() 生产的具体产品,可以用工厂方法模式实现,即每一个产品用一个工厂方法实现。c. 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。d. 抽象工厂不能直接创建产品,只能创建工厂,即抽象工厂创建的产品是工厂。虽然它也定义了创建产品的方法,但需要创建出来的具体的工厂实现,即抽象工厂创建出的工厂创建产品。e. 工厂方法采用的是类继承机制(生成一个子类,重写该工厂方法,在该方法中生产一个对象);而抽象工厂采用的是对象组合机制,专门定义“工厂”对象来负责对象的创建。对象组合的方式就是把“工厂”对象作为参数传递。应用抽象工厂模式可应用:支持多种数据库的数据库接口访问层;界面设计各种风格界面等。源码中通过PC 工厂和手机工厂和预装的操作系统产品来举例实现模式。源码#include <iostream>#include <string>using namespace std;/ 产品class CLinux{public :virtual ~CLinux() {};// 产品使用公共接口virtual void Start() = 0;};class CLinuxMobile : public CLinux{public :CLinuxMobile(){cout << "create linux mobile." << endl;}virtual ~CLinuxMobile() {};virtual void Start(){cout << "linux mobile start." << endl;};};class CLinuxPC : public CLinux{public :CLinuxPC(){cout << "create linux PC." << endl;}virtual ~CLinuxPC() {};virtual void Start(){cout << "linux PC start." << endl;};};class CWindows{public :virtual ~CWindows() {};// 产品使用公共接口virtual void Start() = 0;};class CWindowsMobile : public CWindows{public :CWindowsMobile(){cout << "create windows mobile." << endl;}virtual ~CWindowsMobile() {};virtual void Start(){cout << "windows mobile start." << endl;};};class CWindowsPC : public CWindows{public :CWindowsPC(){cout << "create windows PC." << endl;}virtual ~CWindowsPC() {};virtual void Start(){cout << "windows PC start." << endl;};};工厂class CFactory{public :virtual ~CFactory(){};// 产品族有个产品组件virtual CLinux* CreateLinux() = 0;virtual CWindows* CreateWindows() = 0;};class CMobileFactory : public CFactory{public :CMobileFactory(){cout << "create mobile factory." << endl;}virtual ~CMobileFactory(){};virtual CLinux* CreateLinux(){return new CLinuxMobile;};virtual CWindows* CreateWindows(){return new CWindowsMobile;};};class CPCFactory : public CFactory{public :CPCFactory(){cout << "create PC factory." << endl;}virtual ~CPCFactory(){};virtual CLinux* CreateLinux(){return new CLinuxPC;};virtual CWindows* CreateWindows(){return new CWindowsPC;};};void Test(CFactory* pFactory){CLinux* pLinux = NULL;CWindows* pWindows = NULL;pLinux = pFactory->CreateLinux();pWindows = pFactory->CreateWindows();pLinux->Start();pWindows->Start();delete pWindows;delete pLinux;};int main(){CFactory* pFactory = NULL;// 手机工厂。生产手机产品族,种类有 Linux 和 WindowspFactory = new CMobileFactory;Test(pFactory);delete pFactory;cout << endl;//PC 工厂。生产 PC 产品族,种类有 Linux 和 WindowspFactory= new CPCFactory;Test(pFactory);delete pFactory;system("pause");return 0;}输出:create mobile factory.create linux mobile.create windows mobile.linux mobile start.windows mobile start.create PC factory.create linux PC.create windows PC.linux PC start.windows PC start.
-
顶
- 1
-
踩