文档章节

设计模式(1)--工厂模式

r
 ranjiewen
发布于 2016/11/03 23:52
字数 3201
阅读 2
收藏 0

      前段时间也简单的了解过设计模式,一直都没有认真的学习过,不过打算连续学习一下;

      主要借鉴了这两个地方的博客:http://www.cnblogs.com/dongsheng/category/776522.html  主要讲了设计模式的框架,后面的文章也有代码实现;在UML实现时加入了客户端

                                            http://www.jellythink.com/archives/tag/designpattern/page/2 这个是原创博客的分享网站,讲的设计模式通俗易懂,很好理解,两者配合学习,应该效果更好!

      工厂模式有一种非常形象的描述,建立对象的类就如一个工厂,而需要被建立的对象就是一个个产品;在工厂中加工产品,使用产品的人,不用在乎产品是如何生产出来的。从软件开发的角度来说,这样就有效的降低了模块之间的耦合。

      做了一个windows 8平台的阅读器。首先,需要将电子书中的内容渲染到屏幕上,而电子书每一页都包含各种各样的内容,比如:图形、图像和文字等等;不同的内容,就是不同的对象;在将不同的内容渲染到屏幕上之前,就需要new操作,建立不同的对象,然后再在屏幕上进行描绘。这个时候,就需要进行很多new操作,new操作分布在代码的不同地方,管理起来很麻烦,而且也很乱,到后期扩展和维护的时候,有的时候,对象多的让开发人员不知道这个对象是干什么的,这就增加了难度;同时,new操作,都会有对应的异常处理,最后,就会发现,在代码中,new了一个对象,然后,就跟着一段异常处理代码,这时编码变的极其混乱和臃肿。那么怎么办?怎么办?此时,我们需要一个新的类,专门从事对象的建立和释放,之后,对象的各种操作,和这个类没有任何关系。这个专门建立对象的类,向外暴漏创建对象的接口,供外部调用。

对于工厂模式,具体上可以分为三类:

  1. 简单工厂模式;
  2. 工厂方法模式;
  3. 抽象工厂模式。

对于上面的三种工厂模式,从上到下逐步抽象,并且更具一般性。

UML类图

Simply Factory Design

ProductA、ProductB和ProductC继承自Product虚拟类,Show方法是不同产品的自描述;Factory依赖于ProductA、ProductB和ProductC,Factory根据不同的条件创建不同的Product对象。

适用场合

  1. 在程序中,需要创建的对象很多,导致对象的new操作多且杂时,需要使用简单工厂模式;
  2. 由于对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。
#include <iostream>
#include <vector>
using namespace std;

typedef enum ProductTypeTag
{
    TypeA,
    TypeB,
    TypeC
}PRODUCTTYPE;

// Here is the product class
class Product
{
public:
    virtual void Show() = 0;
};

class ProductA : public Product
{
public:
    void Show()
    {
        cout<<"I'm ProductA"<<endl;
    }
};

class ProductB : public Product
{
public:
    void Show()
    {
        cout<<"I'm ProductB"<<endl;
    }
};

class ProductC : public Product
{
public:
    void Show()
    {
        cout<<"I'm ProductC"<<endl;
    }
};

// Here is the Factory class
class Factory
{
public:
    Product* CreateProduct(PRODUCTTYPE type)
    {
        switch (type)
        {
        case TypeA:
            return new ProductA();

        case TypeB:
            return new ProductB();

        case TypeC:
            return new ProductC();

        default:
            return NULL;
        }
    }
};

int main(int argc, char *argv[])
{
    // First, create a factory object
    Factory *ProductFactory = new Factory();
    Product *productObjA = ProductFactory->CreateProduct(TypeA);
    if (productObjA != NULL)
        productObjA->Show();

    Product *productObjB = ProductFactory->CreateProduct(TypeB);
    if (productObjB != NULL)
        productObjB->Show();

    Product *productObjC = ProductFactory->CreateProduct(TypeC);
    if (productObjC != NULL)
        productObjC->Show();

    delete ProductFactory;
    ProductFactory = NULL;

    delete productObjA;
    productObjA = NULL;

    delete productObjB;
    productObjB = NULL;        

    delete productObjC;
    productObjC = NULL;

    return 0;
}

     

      由于简单工厂模式的局限性,比如:工厂现在能生产ProductA、ProductB和ProductC三种产品了,此时,需要增加生产ProductD产品;那么,首先是不是需要在产品枚举类型中添加新的产品类型标识,然后,修改Factory类中的switch结构代码。是的,这种对代码的修改,对原有代码的改动量较大,易产生编码上的错误(虽然很简单,如果工程大了,出错也是在所难免的!!!)。这种对代码的修改是最原始,最野蛮的修改,本质上不能称之为对代码的扩展。同时,由于对已经存在的函数进行了修改,那么以前进行过的测试,都将是无效的,所有的测试,都将需要重新进行,所有的代码都需要进行重新覆盖。这种,增加成本,不能提高效率的事情,在公司是绝对不允许的(除非昏庸的PM)。出于种种原因,简单工厂模式,在实际项目中使用的较少。那么该怎么办?怎么办呢?需要对原有代码影响降到最小,同时能对原有功能进行扩展。

UML类图

      那么今天介绍的工厂方法模式,就隆重登场了。它只是对简单工厂模式的扩展,在GOF的介绍中,它们是合并在一起的,而我则是单独分开进行讲解的,就是为了区分二者的利弊,便于大家在实际项目中进行更好的把握与应用。工厂方法模式是在简单工厂模式的基础上,对“工厂”添加了一个抽象层。将工厂共同的动作抽象出来,作为抽象类,而具体的行为由子类本身去实现,让子类去决定生产什么样的产品。

果冻想 | 一个原创文章分享网站

      如图,FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。由于FactoryA、FactoryB和FactoryC之间没有关系,当加入FactoryC加入时,对FactoryA和FactoryB的工作没有产生任何影响,那么对代码进行测试时,只需要单独对FactoryC和ProductC进行单元测试,而FactoryA和FactoryB则不用进行测试,则可省去大量无趣无味的测试工作。

适用场合

      工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

  1. 在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式;
  2. 产品结构较复杂的情况下,可以使用工厂方法模式;

由于使用设计模式是在详细设计时,就需要进行定夺的,所以,需要权衡多方面的因素,而不能为了使用设计模式而使用设计模式。

#include <iostream>
using namespace std;

class Product
{
public:
    virtual void Show() = 0;
};

class ProductA : public Product
{
public:
    void Show()
    {
        cout<< "I'm ProductA"<<endl;
    }
};

class ProductB : public Product
{
public:
    void Show()
    {
        cout<< "I'm ProductB"<<endl;
    }
};

class Factory
{
public:
    virtual Product *CreateProduct() = 0;
};

class FactoryA : public Factory
{
public:
    Product *CreateProduct()
    {
        return new ProductA ();
    }
};

class FactoryB : public Factory
{
public:
    Product *CreateProduct()
    {
        return new ProductB ();
    }
};

int main(int argc , char *argv [])
{
    Factory *factoryA = new FactoryA ();
    Product *productA = factoryA->CreateProduct();
    productA->Show();

    Factory *factoryB = new FactoryB ();
    Product *productB = factoryB->CreateProduct();
    productB->Show();

    if (factoryA != NULL)
    {
        delete factoryA;
        factoryA = NULL;
    }

    if (productA != NULL)
    {
        delete productA;
        productA = NULL;
    }

    if (factoryB != NULL)
    {
        delete factoryB;
        factoryB = NULL;
    }

    if (productB != NULL)
    {
        delete productB;
        productB = NULL;
    }
    return 0;
}

      C++设计模式——工厂方法模式,我们可能会想到,后期产品会越来越多了,建立的工厂也会越来越多,工厂进行了增长,工厂变的凌乱而难于管理;由于工厂方法模式创建的对象都是继承于Product的,所以工厂方法模式中,每个工厂只能创建单一种类的产品,当需要生产一种全新的产品(不继承自Product)时,发现工厂方法是心有余而力不足。

      举个例子来说:一个显示器电路板厂商,旗下的显示器电路板种类有非液晶的和液晶的;这个时候,厂商建造两个工厂,工厂A负责生产非液晶显示器电路板,工厂B负责生产液晶显示器电路板;工厂一直就这样运行着。有一天,总经理发现,直接生产显示器的其余部分也挺挣钱,所以,总经理决定,再建立两个工厂C和D;C负责生产非液晶显示器的其余部件,D负责生产液晶显示器的其余部件。此时,旁边参谋的人就说了,经理,这样做不好,我们可以直接在工厂A中添加一条负责生产非液晶显示器的其余部件的生产线,在工厂B中添加一条生产液晶显示器的其余部件的生产线,这样就可以不用增加厂房,只用将现有厂房进行扩大一下,同时也方便工厂的管理,而且生产非液晶显示器电路板的技术人员对非液晶显示的其余部件的生产具有指导的作用,生产液晶显示器电路板也是同理。总经理发现这是一个不错的主意。

      再回到软件开发的过程中来,工厂A和B就是之前所说的C++设计模式——工厂方法模式;总经理再次建立工厂C和D,就是重复C++设计模式——工厂方法模式,只是生产的产品不同罢了。这样做的弊端就如参谋所说的那样,增加了管理成本和人力成本。在面向对象开发的过程中,是很注重对象管理和维护的,对象越多,就越难进行管理和维护;如果工厂数量过多,那么管理和维护的成本将大大增加;虽然生产的是不同的产品,但是可以二者之间是有微妙的关系的,如参谋所说,技术人员的一些技术经验是可以借鉴的,这就相当于同一个类中的不同对象,之间是可以公用某些资源的。那么,增加一条流水线,扩大厂房,当然是最好的主意了。

实际问题已经得到了解决,那么如何使用设计模式模拟这个实际的问题呢?那就是接下来所说的抽象工厂模式。

UML类图

       现在要讲的抽象工厂模式,就是工厂方法模式的扩展和延伸,但是抽象工厂模式,更有一般性和代表性;它具有工厂方法具有的优点,也增加了解决实际问题的能力。

Abstract Factory Pattern

       如图所示,抽象工厂模式,就好比是两个工厂方法模式的叠加。抽象工厂创建的是一系列相关的对象,其中创建的实现其实就是采用的工厂方法模式。在工厂Factory中的每一个方法,就好比是一条生产线,而生产线实际需要生产什么样的产品,这是由Factory1和Factory2去决定的,这样便延迟了具体子类的实例化;同时集中化了生产线的管理,节省了资源的浪费。

适用场合

       工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组(有多个种类)相关的产品,为它们提供创建的接口;就是当具有多个抽象角色时,抽象工厂便可以派上用场。

 

#include <iostream>
using namespace std;

// Product A
class ProductA
{
public:
    virtual void Show() = 0;
};

class ProductA1 : public ProductA
{
public:
    void Show()
    {
        cout<<"I'm ProductA1"<<endl;
    }
};

class ProductA2 : public ProductA
{
public:
    void Show()
    {
        cout<<"I'm ProductA2"<<endl;
    }
};

// Product B
class ProductB
{
public:
    virtual void Show() = 0;
};

class ProductB1 : public ProductB
{
public:
    void Show()
    {
        cout<<"I'm ProductB1"<<endl;
    }
};

class ProductB2 : public ProductB
{
public:
    void Show()
    {
        cout<<"I'm ProductB2"<<endl;
    }
};

// Factory
class Factory
{
public:
    virtual ProductA *CreateProductA() = 0;
    virtual ProductB *CreateProductB() = 0;
};

class Factory1 : public Factory
{
public:
    ProductA *CreateProductA()
    {
        return new ProductA1();
    }

    ProductB *CreateProductB()
    {
        return new ProductB1();
    }
};

class Factory2 : public Factory
{
    ProductA *CreateProductA()
    {
        return new ProductA2();
    }

    ProductB *CreateProductB()
    {
        return new ProductB2();
    }
};

int main(int argc, char *argv[])
{
    Factory *factoryObj1 = new Factory1();
    ProductA *productObjA1 = factoryObj1->CreateProductA();
    ProductB *productObjB1 = factoryObj1->CreateProductB();

    productObjA1->Show();
    productObjB1->Show();

    Factory *factoryObj2 = new Factory2();
    ProductA *productObjA2 = factoryObj2->CreateProductA();
    ProductB *productObjB2 = factoryObj2->CreateProductB();

    productObjA2->Show();
    productObjB2->Show();

    if (factoryObj1 != NULL)
    {
        delete factoryObj1;
        factoryObj1 = NULL;
    }

    if (productObjA1 != NULL)
    {
        delete productObjA1;
        productObjA1= NULL;
    }

    if (productObjB1 != NULL)
    {
        delete productObjB1;
        productObjB1 = NULL;
    }

    if (factoryObj2 != NULL)
    {
        delete factoryObj2;
        factoryObj2 = NULL;
    }

    if (productObjA2 != NULL)
    {
        delete productObjA2;
        productObjA2 = NULL;
    }

    if (productObjB2 != NULL)
    {
        delete productObjB2;
        productObjB2 = NULL;
    }
}

 

本文转载自:http://www.cnblogs.com/ranjiewen/p/5344617.html

上一篇: 八大排序算法
下一篇: strcpy函数的实现
r
粉丝 1
博文 203
码字总数 28
作品 0
武汉
程序员
私信 提问
《PHP设计模式大全》系列分享专栏

《PHP设计模式大全》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页...

kaixin_code
2018/11/06
185
0
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
2018/06/24
0
0
《JavaScript设计模式与开发实践》原则篇(2)—— 最少知识原则

最少知识原则(LKP)说的是一个软件实体应当尽可能少地与其他实体发生相互作用。这 里的软件实体是一个广义的概念,不仅包括对象,还包括系统、类、模块、函数、变量等。 单一职责原则指导我们...

嗨呀豆豆呢
2018/12/30
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
296
0
PHP设计模式(一):简介及创建型模式

我们分三篇文章来总结一下设计模式在PHP中的应用,这是第一篇创建型模式。 一、设计模式简介 首先我们来认识一下什么是设计模式: 设计模式是一套被反复使用、容易被他人理解的、可靠的代码设...

juhenj
2014/05/15
286
2

没有更多内容

加载失败,请刷新页面

加载更多

【2019个推开发者节】航母级APP都在用的SDK现在全部免费,35岁老程序员表示第一次见!

1024程序员节来了 双11近了 各路满减、折扣、领券、秒杀、集赞 营销玩法猛于虎,一看优惠两毛五 日常拼命赶“需求” 修“Bug”的开发者们 想找个好用又不贵的工具太难了 亲爱的开发者们,不要...

个推
37分钟前
9
0
Ceph对可用存储空间的校验与控制

Ceph一共使用了四个配置对可用存储空间进行校验并实施控制,如下: mon_osd_full_ratio:集群中的任一OSD空间使用率大于等于此数值时,集群将被标记为Full,此时集群将停止接受来自客户端的写...

浪里个浪浪
38分钟前
11
0
工厂方法模式

1.定义:创建一个接口,协助创建其它对象 2.优缺点 优: a.用户只需要知道这个工厂是创建哪种对象的,不需要知道创建的过程 b.满足开闭原则(开闭原则:对扩展开放,对修改关闭,即增加类可以...

wen123
40分钟前
6
0
Bootstrap Table -detailView和detailFilter的使用

查看表格 detailFilter 属性:data-detail-filter Type:Function Default:function(index,row){ return true} detailView 属性:data-detail-view Type:Boolean Default:false <table id="ta......

tianyawhl
45分钟前
4
0
场效应管的注意事项

  (1)为了安全使用场效应管,在线路的设计中不能超过管的耗散功率,最大漏源电压、最大栅源电压和最大电流等参数的极限值。   (2)各类型场效应管在使用时,都要严格按要求的偏置接入...

仙溪
47分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部