设计模式(2):工厂模式(Factory Method)

1. 说明

关于设计模式的说明和解释主要是学习的《设计模式 可复用面向对象软件的基础》一书,代码示例则主要是来自于设计模式|菜鸟教程网站,将该网站中原有的java示例改写成c++基础的代码,用以加深自己的理解,方便学习之用。看官们也可直接参考这两个来源。

2. 工厂模式说明

什么是工厂模式
工厂模式是创建型模式的一种,它通过一个抽象的通用接口屏蔽了具体类的实现细节,这样在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类。

适用的场合
当一个类不知道它所必须创建的对象的类的时候;
当一个类希望由它的子类来指定它所创建的对象的时候;
当类将创建对象的职责委托给多个子类中的某一个,并且你希望将哪一个子类是代理者这一信息局部化的时候。

优点
屏蔽了多个子类的实现细节,要创建一个类时只要调用同一个接口类就行了;
可扩展性好,当需要增加某一类产品时,只要增加一个工厂类就可以了;

缺点
增加一个产品时要分别增加具体的产品类和一个工厂接口,这样就增加了更多的工作内容。

3. 示例说明

3.1 框架

纸上得来终觉浅,绝知此事要躬行。光看文字说明反正我是觉得云里雾里的,下面就用一个具体的实例来说明一下工厂模式的简单实现。这个示例中我们将定义两个工厂分别实现Color和Shape类和成员函数。程序框架如下图:
在这里插入图片描述


3.2 代码实现

基类

Shape.h

#ifndef __SHAPE__
#define __SHAPE__

class Shape{
    public:
        virtual void draw() = 0;
};

#endif

class Shape是所有具体形状(Rectangle, Square, Circle)的基类,只包含一个没有实现的虚函数draw(),该函数在每一个具体类中分别有不同的实现。
它是提供给上层的接口,即上一层调用不同类的函数时都是通过这个类的接口调用的。

产品类的实现

Rectangle.h

#ifndef __RECTANGLE__
#define __RECTANGLE__

#include <iostream>

#include "Shape.h"

class Rectangle : public Shape{
    public:
        Rectangle(){};
        void draw() {std::cout << "Inside Rectangle::draw()." << std::endl;};
};

#endif

Square.h

#ifndef __SQUARE__
#define __SQUARE__

#include <iostream>

#include "Shape.h"

class Square : public Shape{
    public:
        Square(){};
        void draw() {std::cout << "Inside Square::draw()." << std::endl;}
};

#endif

Circle.h

#ifndef __CIRCLE__
#define __CIRCLE__

#include <iostream>

#include "Shape.h"

class Circle : public Shape{
    public:
        Circle(){};
        void draw() {std::cout << "Inside Circle::draw()" << std::endl;};
};

#endif

Rectangle/Square/Circle是继承自Shape类的三个具体的实现,它们分别实现了draw()函数。在实际调用时也是分别进入到这三个类里面调用draw()。

工厂类的实现

Factory.h

#ifndef __FACTORY__
#define __FACTORY__

#include <string>

#include "Shape.h"
#include "Color.h"

using namespace std;

class ShapeFactory {
    public:
        Shape *GetShape(string shapeType);
};

class ColorFactory {
    public:
        Color *GetColor(string color);
};
#endif

Factory.cpp

#include <cstddef>
#include <string>

#include "Circle.h"
#include "Rectangle.h"
#include "Square.h"
#include "Red.h"
#include "Green.h"
#include "Blue.h"
#include "Factory.h"

Shape *ShapeFactory::GetShape(string shapeType)
{
    string str1 = "Circle";
    string str2 = "Rectangle";
    string str3 = "Square";

    if (shapeType == str1){
        return new Circle();
    }else if (shapeType == str2){
        return new Rectangle();
    }else if (shapeType == str3){
        return new Square();
    }

    return NULL;
}

Color *ColorFactory::GetColor(string color)
{
    string str1 = "Red";
    string str2 = "Green";
    string str3 = "Blue";

    if (color == str1){
        return new Red();
    }else if (color == str2){
        return new Green();
    }else if (color == str3){
        return new Blue();
    }

    return NULL;
}

这里实现了Shape的工厂类,该类只包含一个函数GetShape(),根据输入的参数不同分别返回不同的形状类(Rectangle/Square/Circle)的实例,但是这些实例的类型都是Shape *。这样做的好处是在应用层调用时不必再关心具体类的具体实现,只要用同一个函数得到同一种类型的实例,再通过这个实例去调用同样的成员函数。

Color工厂类的实现差不多,这里是用于对比说明。

Color类相关代码

Color.h

#ifndef __COLOR__
#define __COLOR__

class Color {
    public:
        virtual void fill() = 0;
};

#endif

Red.h

#ifndef __RED__
#define __RED__

#include <iostream>

#include "Color.h"

class Red : public Color{
    public:
        Red(){};
        void fill() {std::cout << "Inside Red::fill()" << std::endl;};
};

#endif

Blue.h

#ifndef __BLUE__
#define __BLUE__

#include <iostream>

#include "Color.h"

class Blue : public Color{
    public:
        Blue(){};
        void fill() {std::cout << "Inside Blue::fill()" << std::endl;}
};

#endif

Green.h

#ifndef __GREEN__
#define __GREEN__

#include <iostream>

#include "Color.h"

class Green : public Color{
    public:
        Green(){};
        void fill() {std::cout << "Inside Green::fill()" << std::endl;};
};

#endif


应用程序代码

demo.cpp

#include "Factory.h"

int main(int argc, char **argv)
{
    ShapeFactory sf;
    Shape *s1 = sf.GetShape("Rectangle");
    s1->draw();

    Shape *s2 = sf.GetShape("Square");
    s2->draw();

    Shape *s3 = sf.GetShape("Circle");
    s3->draw();

    ColorFactory cf;
    Color *c1 = cf.GetColor("Red");
    c1->fill();

    Color *c2 = cf.GetColor("Blue");
    c2->fill();

    Color *c3 = cf.GetColor("Green");
    c3->fill();

    return 0;
}

demo首先生成一个工厂类的实例sf,调用sf的GetShape()函数生成不同的Shape实例,分别调用它们的draw()函数。注意,这里虽然是不同的Shape实例,但是它们都是Shape *类型的,也就说都是按照同样的接口调用的。

编译

g++ *.cpp -o demo


运行

$ ./demo
Inside Rectangle::draw().
Inside Square::draw().
Inside Circle::draw()
Inside Red::fill()
Inside Blue::fill()
Inside Green::fill()


4. 分析总结

工厂模式的特点在于:

  1. 定义的基类要抽象出所有的具体子类的功能函数,以便使用统一的接口调用,如这里的draw();
  2. 如果某些子类拥有独有的功能函数,那么其他相关的子类也应该要有该函数名称的实现,哪怕只是return NULL;
  3. 独有功能函数过多,会额外增加大量无效代码;
  4. 不同种类的产品,需要重新实现一套工厂类+基类+子类的;

参考资料

《设计模式 可复用面向对象软件的基础》
工厂模式——菜鸟教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

翔底

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

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

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

打赏作者

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

抵扣说明:

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

余额充值