zoukankan      html  css  js  c++  java
  • 设计模式之工厂模式

    一、概述

       与简单工厂模式相比,工厂模式使一个类的实例化延迟到了其子类处理,改善了简单工厂对修改不能关闭的问题。
       这里我们要关注的是代码的变化:与简单工厂模式相比,与产品类相关的类保持不变,但与工厂类相关的类会有变化。
       所以这里有关产品的类的实现完全照搬了简单工厂的代码。我们只要关注工厂类的变化,就可理解工厂模式的真正意图。

       优点:
       1)解决了简单工厂的修改不能关闭的问题,系统新增产品时,新增一个产品工厂即可,工厂基类不受影响。
           也就是说:当新增产品时,就由工厂类派生出一些子类,让这些子类生产(new)其所对应的产品。当新增产品的时候,工厂类保持不变,只要增加一工厂派生类即可完成。
       缺点:
       1)无法创建多个系列的产品
       2)当一个类不知道它所必须创建的对象的类的时候
       3)当一个类希望由它的子类来指定它所创建的对象的时候
       4)当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

        简而言之:
        工厂模式的做法相当于把简单工厂调用产品的操作放到了工厂模式的派生类里面。我们所做的就是定义一个创建所有产品的公共接口,供工厂派生类使用。
        Product类簇保持不变,提供产品的公共属性接口;结构上继续保持2层结构。
        Factory类簇发生改变,提供产品的公共创建接口;结构上变成2层结构:工厂类-工厂子类
       

    二、类图

    三、代码

    IProduct.h,IProduct.cpp (见简单工厂模式代码)

    ConcreteProductA.h,ConcreteProductA.cpp (同上)

    ConcreteProductB.h, ConcreteProductB.cpp (同上)

    ConcreteProductNew.h

    #pragma once
    
    #include "IProduct.h"
    //新增产品时:增加产品派生类:CConcreteProductNew
    
    class CConcreteProductNew :public IProduct
    {
    public:
    	CConcreteProductNew();
    	virtual ~CConcreteProductNew();
    
    public:
    	virtual void Function();
    };
    

    ConcreteProductNew.cpp

    #include "ConcreteProductNew.h"
    
    CConcreteProductNew::CConcreteProductNew()
    {
    	cout<<__FUNCTION__<<endl;
    }
    
    CConcreteProductNew::~CConcreteProductNew()
    {
    	cout<<__FUNCTION__<<endl;
    }
    
    void CConcreteProductNew::Function()
    {
    	cout<<__FUNCTION__<<endl;
    }
    

    IFactory.h

    #include "IProduct.h"
    /*
    	简单工厂类:是用来专门调用产品的,当有新的产品需求时,就会在工厂类内添加代码,破坏了工厂模式的封装性
    				也就是说:这是一种“工厂类”对应“产品派生类”的方式,一旦有新的产品类,就会动到工厂类。
    	工厂类:    提供了一个调用产品的虚接口,将自身已有的产品以派生子类的方式保护起来,若有新的产品需求则会以新的派生类加以实现,而不会动到原有的代码,保证了封装性。
    	            也就是说:这是一种:“工厂派生类”对应其“产品派生类”的方式,当有新的产品类时,只需要从工厂基类中派生出子类加以实现就行了。
    */
    class IFactory
    {
    public:
    	IFactory();
    	virtual ~IFactory();
    
    public:
    	virtual IProduct *CreateProduct(int nType = 0) = 0;
    
    };
    

     IFactory.cpp

    #include "IFactory.h"
    
    IFactory::IFactory()
    {
    
    }
    
    IFactory::~IFactory()
    {
    
    }
    

     ConcreteFactory1.h

    #pragma  once
    
    #include "IFactory.h" //工厂派生类:工厂基类,
    
    //下面的头文件是应该放在cpp文件里面的
    #include "ConcreteProductA.h"
    #include "ConcreteProductB.h"
    
    class ConcreteFactory1 :public IFactory
    {
    public:
    	ConcreteFactory1();
    	virtual ~ConcreteFactory1();
    
    public:
    	virtual IProduct *CreateProduct(int nType = 0);
    };
    

     ConcreteFactory1.cpp

    #include "ConcreteFactory1.h"
    
    ConcreteFactory1::ConcreteFactory1()
    {
    
    }
    
    ConcreteFactory1::~ConcreteFactory1()
    {
    
    }
    
    IProduct *ConcreteFactory1::CreateProduct(int nType)
    {
    	IProduct *ptr = NULL;
    
    	switch (nType)
    	{
    	case 0:
    		ptr = new CConcreteProductA();
    		break;
    
    	case 1:
    		ptr = new CConcreteProductB();
    		break;
    
    	default:
    		ptr = new CConcreteProductA();
    	}
    
    	return ptr;
    }
    

     ConcreteFactoryNew.h

    #pragma once
    
    #include "IFactory.h"
    
    //这个头文件,应该放在cpp内
    #include "ConcreteProductNew.h"
    
    //新增产品时,增加工厂派生类: ConcreteFactoryNew
    class CConcreteFactoryNew :public IFactory
    {
    public:
    	CConcreteFactoryNew();
    	virtual ~CConcreteFactoryNew();
    
    public:
    	virtual IProduct *CreateProduct(int nType = 0);
    };
    

    ConcreteFactoryNew.cpp

    #include "ConcreteFactoryNew.h"
    
    CConcreteFactoryNew::CConcreteFactoryNew()
    {
    
    }
    
    CConcreteFactoryNew::~CConcreteFactoryNew()
    {
    
    }
    
    IProduct *CConcreteFactoryNew::CreateProduct(int nType)
    {
    	return new CConcreteProductNew();
    }
    

     main.cpp

    #include "IFactory.h"
    #include "IProduct.h"
    
    #include "ConcreteFactory1.h"
    #include "ConcreteFactoryNew.h"
    
    #include <iostream>
    using namespace std;
    
    int main()
    {	
    	//可以当作是调用已有产品的工厂接口
    	cout<<"Call inner Product:"<<endl;
    	IFactory *pFactroy = new ConcreteFactory1();
    	IProduct *pProduct = pFactroy->CreateProduct(0);
    	pProduct->Function();
    	delete pProduct;
    	pProduct = NULL;
    
    	pProduct = pFactroy->CreateProduct(1);
    	pProduct->Function();
    	delete pProduct;
    	pProduct = NULL;
    	delete pFactroy;
    	pFactroy = NULL;
    
    	//调用新产品的工厂接口
    	cout<<"Call New Product:"<<endl;
    	pFactroy = new CConcreteFactoryNew;
    	pProduct = pFactroy->CreateProduct();
    	pProduct->Function();
    	delete pProduct;
    	pProduct = NULL;
    	delete pFactroy;
    	pFactroy = NULL;
    
    	return 0;
    }
    

    四、运行结果

    Call inner Product:
    CConcreteProductA::CConcreteProductA
    CConcreteProductA::Function
    CConcreteProductA::~CConcreteProductA
    CConcreteProductB::CConcreteProductB
    CConcreteProductB::Function
    CConcreteProductB::~CConcreteProductB
    Call New Product:
    CConcreteProductNew::CConcreteProductNew
    CConcreteProductNew::Function
    CConcreteProductNew::~CConcreteProductNew
    请按任意键继续. . .

  • 相关阅读:
    Centos常用命令之:文件与目录管理
    Centos常用命令之:ls和cd
    Centos6.9连接工具设置
    CentOS6.9安装
    mysql-5.7.18-winx64 免安装版配置
    Struts1开山篇
    参考用bat文件
    QT界面开发-c++ 如何在Qt中将QVariant转换为QString,反之亦然?【转载】
    QT界面开发-QAxObject 解析 excel 时报错error LNK2019: 无法解析的外部符号
    QT界面开发-QAxObject 读写excel(COM组件)
  • 原文地址:https://www.cnblogs.com/jacklikedogs/p/3807683.html
Copyright © 2011-2022 走看看