zoukankan      html  css  js  c++  java
  • 【转】设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)

    设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)

     

    创建型设计模式总结

    (转载请注明来源 http://www.cnblogs.com/jerry19880126/

    创建型设计模式包括简单工厂模式,普通工厂模式,抽象工厂模式,建造者模式,原型模式和最简单的单例模式。

     

    简单工厂模式(Simple Factory)

     

    从UML图中可以看出,工厂是具体的,Product是抽象的,里面的方法Operation是virtual的,它的三个子类是具体的,子类中的Operation覆盖父类的方法Operation,由多态知识可知,运行时将会调用子类的Operation,父类的Operation只是声明的“接口”。

    多态有三个条件:一是父类的virtual,二是子类的覆盖(要求函数名、参数、返回值都要一模一样),三是父类的指针或引用指向子类的对象。前两个条件已经满足,下面关键是讨论第三个条件。

    第三个条件的关键就是Factory了,Factory能根据客户端的请求,生成不同的具体对象,这可以用flag来标识,假定flag = 1时,生成ConcreteProduct1对象;flag = 2时,生成ConcreteProduct2对象。因此,可以在Factory这样写CreateProduct()。

    Product* CreateProduct(flag)

    {

    Switch(flag)

    case 1: return new ConcreateProduct1(); break;

    case 2: return new ConcreateProduct2(); break;

    case 3:…

    }

     

    在客户端只要用

    Factory f; // 生成factory对象

    f.getProduct(1).Operation();就可以调用ConcreteProduct1的方法了

    f.getProduct(2).Operation();就可以调用ConcreteProudct2的方法了。

     

    这样说来,相信读者已经明白,其实工厂方法就是根据客户端不同的“要求”,产生不同的具体对象,再利用多态特性,调用相应具体对象的方法。

     

    下面给出可执行的源代码,与上述例子不尽相同,但思想是一样的,运行结果如下图所示。

    复制代码
    简单工厂模式
    复制代码

     

    运行结果如下:

     

    (普通)工厂模式(Factory)

    与简单工厂模式换汤不换药,只是把工厂也“抽象”了,UML图如下所示:

     

    从上图可以看出,只不过多出一块抽象工厂而已。抽象工厂提供CreateProduct的虚接口,在ConcreteFactory中实现,为了便于说明问题,这里假定有两个ConcreteFactory,一个是ConcreteFactory1,只生产ConcreteProduct1产品,另一个是ConcreteFactory2,只生产ConcreteProduct2产品。

     

    以ConcreteFactory1为例,代码框架如下:

    class ConcreateFactory1: public Factory

    {

     Product* CreateProduct()

    {

         return new ConcreteProduct1();

    }

    };

     

    在客户端用 Factory *f = new ConcreteFactory1(); f->CreateProduct();就可以得到ConcreteProduct1的对象了。

     

    下面给出可执行的源代码,运行结果的截图放在后面。

    复制代码
    普通工厂模式
    复制代码

     

    运行结果如下:

     

    抽象工厂模式(Abstract Factory)

     

    抽象工厂又是(普通)工厂模式的升级版,但本质是相同的。观察UML图,可以看到不同的地方在于多了一个抽象产品的类

    ConcreateFactory1只生产ProductA1和ProductB1,即下标带“1”的产品。可以预见,在ConcreteFactory1中的两个方法应该如下:

     

    AbstractProductA* CreateProductA()

    {

             return new ProductA1();

    }

    AbstractProductB* CreateProductB()

    {

             return new ProductB1();

    }

     

    ConcreateFactory2中的两个方法类似,只是将最后的下标换成2而已。

     

    下面给出可以执行的源代码,运行截图放在代码的后面。

    复制代码
    抽象工厂模式
    复制代码

     

    运行结果如下:

     

    “工厂系列”设计模式总结

    下面总结一下“工厂系列”设计模式,简单工厂模式只有一份抽象的产品,工厂是具体的;(普通)工厂模式的同样也只有一份抽象的产品,但工厂有抽象的了;抽象工厂模式工厂当然是抽象的,但是它独特的地方在于产品至少有两份是抽象的。

     

    建造者模式(Builder)

     

    建造者模式包含一个抽象的Builder类,还有它的若干子类——ConcreteBuilder,不用理会UML图上的Product,关键是看Director,Director里面的方法Construct()其实包含了Builder指针或引用的形参,由客户端传入某个ConcreateBuilder对象。Construct(Builder* builder)的方法大致如下:

    Construct(Builder* builder)

    {

             Builder->BuildPartA();

             Builder->BuildPartB();

             …

    }

    由多态性可知,客户端传进来的ConcreteBuilder是谁,就调用谁的方法。

     

    可执行的源代码如下,运行结果在源代码的后面。

    复制代码
    建造者模式
    复制代码

     

    运行结果如下:

     

    原型模式(Prototype)

     

    听起来挺玄乎,其实说穿了,就是深拷贝问题。当一个类中包含了指针,那么这个类一定要显示规定三个东西:拷贝构造函数,重载”=”操作符以及析构函数。如果程序员使用编译器默认产生的这三个函数,那么得到的对象是原来对象的“浅拷贝”,即只是简单拷贝了指针的值(只复制了地址),没有复制指针指向空间的内容。“浅拷贝”只会保留最近的修改结果,而且在析构时容易出现重复析构的错误。

    “深拷贝”是相对浅拷贝的概念说的,深拷贝不是简单的拷贝指针的值(地址),而是重新生成了一个新的空间,这个空间里存放的内容与传入类内容是完全相同的。

     

    请看下面“浅拷贝”的实例:

     

    复制代码
    浅拷贝
    复制代码

     

    运行结果为:

     

    可以看到指针值(地址)是相同的,所以是浅拷贝,程序没有出现“请按任意键继续”的提示,说明程序其实是卡死的,原因是重复析构指针p。

     

    再看看“深拷贝”的实例:

    复制代码
    原型模式(深拷贝)
    复制代码

     

    运行结果如下:

     

    可见指针值不同了,说明指向了不同的空间,而且成功显示了“请按任意键继续”的提示符,说明析构也是正常了。但这里的程序还不完整,按照C++的程序风格,还应该重载“=”运算符,这里的练习便留给读者。

     

    单例模式(Singleton)

    顾名思义,就是保证某个类只有一个实例(对象),这个应用还是很广的,假设腾迅想让用户每次只能用一个QQ登陆,就可以用到这个模式。

     

    这个UML图非常简单,可以说也是所有设计模式中最简单的了,所以在面试中,常常被面试官们问起。

    要使一个类只能生成一个对象,就是要限制使用它的构造函数,即将构造函数定义为private或protected的,然后另辟一个公有方法Instance,在这个方法里检查instance(instance是指向本类的一个指针或引用,这在C++语法中是可以的)是否为空指针,若为空指针,则说明是第一次生成对象,那么操作是允许的,instance = new Singleton(),若指针非空,说明在之前已经有一个对象(实例)了,单例模式不允许再次生成实例,因此直接返回之前生成的对象的地址。

    将instance定义成static变量,就更符合“单例”模式了,因为static变量只有一份,它属于这个类,不属于某个对象。相应的Instance()方法应该也定义成static的,用Singleton::Instance()来调用。注意这里的static方法和变量是必须的,如果函数不是static,则要事先生成对象才能调用Instance,就破坏了“单例”的思想了,如果变量不是static,那么静态函数Instance又不能引用非static变量。

     

    下面给出可以执行的源程序:

    复制代码
    单例模式
    复制代码

     

    运行结果为:

     

  • 相关阅读:
    单例设计模式
    网络编程--Socket与ServerSocket
    JDBC连接Oracle数据库
    ObjectInputStream与ObjectOutputStream
    MyBatis的SQL语句映射文件详解(二)----增删改查
    MyBatis的SQL语句映射文件详解
    MyBatis+Spring实现基本CRUD操作
    通俗解释IOC原理
    Git菜鸟
    hibernate连接oracle数据库
  • 原文地址:https://www.cnblogs.com/beipiaoboy/p/3258253.html
Copyright © 2011-2022 走看看