设计模式之工厂模式

一:工厂模式

将实例化具体类的过程交给工厂,你只用告诉它你需要什么样的类型就好了。

比如下面这段代码:

Fruit createFruit(string name) {
    Fruit fruit;

    --------------------------------
    if(name == "Apple") {
        fruit = new Apple();
    }
    else if(name == "Banana") {
        fruit = new Banana();
    }
    else if(name == "peach") {
        fruit = peach();
    }
    ---------------------------------
    fruit.cut();      //将水果切块
    fruit.box();      //将水果装盒

    return fruit;
}

如果我将上面代码片段中两条横线之间的代码实现为另一个方法叫FruitFactory,如下所示:

Fruit FruitFactory(string name) {
    Fruit fruit;

    if(name == "Apple") {
        fruit = new Apple();
    }
    else if(name == "Banana") {
        fruit = new Banana();
    }
    else if(name == "peach") {
        fruit = peach();
    }
    return fruit;
}

那原来的类就变成了下面这个样子:

Fruit createFruit(string name) {
    Fruit fruit;

    fruit = FruitFactory("Apple");  //创建水果
    fruit.cut();                    //将水果切块
    fruit.box();                    //将水果装盒

    return fruit;
}

好,如果上面的你都理解了,那你就算学会工厂模式了,据说它更像一种编程习惯。

二:为什么要把上面的代码分离出去?

  • 将创建对象的代码集中在一个对象或者方法中,可以避免代码的重复,并且更加方便对象的维护,如果以后别的文件中也需要创建对象,只用调用FruitFactory方法就行了。
  • 分离实现了解耦,现在水果的创建和水果其它操作(切、装盒)是分开的,假设我们要加新品种的水果,那只用在FruitFactory中加入相应代码就行了。

三:我们开一家水果店吧!

这里写图片描述

我们将上面的FruitFactory抽象成了现在的水果店基类。因为可能不同的水果店有不同的水果,比如北京的水果店上海的水果店可能供应的品种是不同的,那它们各自的实现方法createFruit()中不应该都包含所有水果的实现方法。现在我们要订水果怎么办呢?

FruitStore *bjFruitStore = new BJFruitStore(); //新建一个北京的水果店,不要惊奇呀,你都用工厂模式了,开个水果店不很正常吗。
bjFruitStore->orderFruit("Apple"); //预定一个北京水果店的苹果。

四:具体的实现

这次是c++实现:

Fruit.h

#include<iostream>
#include<string>

#ifndef _FRUIT_H
#define _FRUIT_H

class Fruit {
public:
    void cut() {
        std::cout << "Fruit is cutt" << std::endl;
    }
    void box() {
        std::cout << "Fruit is box" << std::endl;
    }
    std::string name;
};

#endif

Apple.h

#include<iostream>
#include<string>
#include"Fruit.h"

#ifndef _APPLE_H
#define _APPLE_H

class Apple: public Fruit{
public:
    Apple(){
        name = "Apple";
    }

};

#endif

Banana.h

#include"Fruit.h"

#ifndef _BANANA_H
#define _BANANA_H

class Banana:public Fruit {
public:
    Banana(){
        name = "Banana";
    }
};

#endif

FruitStore.h

#include<iostream>
#include<string>
#include"Fruit.h"

#ifndef _FRUITSTORE_H
#define _FRUITSTORE_H

class FruitStore {
public:
    void orderFruit(std::string name) {
        Fruit *fruit;
        fruit = createFruit(name);
        fruit->cut();
        fruit->box();
    }
    virtual Fruit *createFruit(std::string name) = 0; //纯虚函数
private:

};


#endif

BJFruitStore.h

#include<iostream>
#include<string>
#include"FruitStore.h"
#include"Apple.h"
#include"Banana.h"


#ifndef _BJFRUITSTORE_H
#define _BJFRUITSTORE_H

class BJFruitStore: public FruitStore {
public:
    Fruit* createFruit(std::string name){
        if(name == "Apple") {
            std::cout << "Created Apple" << std::endl;
            return new Apple();
        }else if(name == "Banana") {
            std::cout << "Created Banana" << std::endl;
            return new Banana();
        }
    }

};

#endif

main.h

#include<iostream>
#include"FruitStore.h"
#include"BJFruitStore.h"

int main(int argc,char *argv[])
{
    FruitStore *fs = new BJFruitStore();
    fs->orderFruit(std::string("Apple"));
    std::cout << "After a While..." <<std::endl;
    fs->orderFruit(std::string("Banana"));
    return 0;
}

这里写图片描述

五:总结

  • 尽量让类派生自接口,而不是具体类,使用组合而不是继承。
  • 避免派生类覆盖基类中的方法,如果需要覆盖,那这个方法就抽象的不合理。
  • 最好将new交给工厂去管理。

posted on 2016-12-06 20:44  杨博东的博客  阅读(24)  评论(0编辑  收藏  举报

导航