`
isiqi
  • 浏览: 16072360 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

设计模式(四)factory,Polymorphic factories,Abstract factories

阅读更多

强制一个通用的工厂来创建对象,而不允许将创建对象的代码散布于整个系统。如果程序中所有需要创建对象的代码都转到这个工厂执行,那么在增加新对象时所要做的全部工作就是只需修改工厂。


//: C10:ShapeFactory1.cpp
#include <iostream>
#include <stdexcept>
#include <cstddef>
#include <string>
#include <vector>
#include "../purge.h"
using namespace std;

class Shape {
public:
    virtual void draw() = 0;
    virtual void erase() = 0;
    virtual ~Shape() {}
    class BadShapeCreation : public logic_error {
    public:
        BadShapeCreation(string type)
            : logic_error("Cannot create type " + type) {}
    };
    static Shape* factory(const string& type)
        throw(BadShapeCreation);
};

class Circle : public Shape {
    Circle() {} // Private constructor
    friend class Shape;
public:
    void draw() { cout << "Circle::draw" << endl; }
    void erase() { cout << "Circle::erase" << endl; }
    ~Circle() { cout << "Circle::~Circle" << endl; }
    };

class Square : public Shape {
    Square() {}
    friend class Shape;
public:
    void draw() { cout << "Square::draw" << endl; }
    void erase() { cout << "Square::erase" << endl; }
    ~Square() { cout << "Square::~Square" << endl; }
};

Shape* Shape::factory(const string& type)
    throw(Shape::BadShapeCreation) {
        if(type == "Circle") return new Circle;
        if(type == "Square") return new Square;
        throw BadShapeCreation(type);
}

char* sl[] = { "Circle", "Square", "Square",
    "Circle", "Circle", "Circle", "Square" };

int main() {
    vector<Shape*> shapes;
    try {
        for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++)
            shapes.push_back(Shape::factory(sl[i]));
    } catch(Shape::BadShapeCreation e) {
        cout << e.what() << endl;
        purge(shapes);
        return EXIT_FAILURE;
    }
    for(size_t i = 0; i < shapes.size(); i++) {
        shapes[i]->draw();
        shapes[i]->erase();
    }
    purge(shapes);
} ///:~

函数factory()允许以一个参数来决定创建何种类型的Shape。在这里,参数类型为string,
也可以是任何数据集。在添加新的Shape类型时,函数factory()是当前系统中惟一需要修改
的代码。(对象的初始化数据大概也可以由系统外获得,而不必像本例中那样来自硬编码数
组。)
这样的设计还有另外一个重要的含义--基类Shape现在必须了解每个派生类的细节--这
是面向对象设计试图避免的一个性质。对于结构框架或者任何类库来说都应该支持扩充,但
这样一来,系统很快就会变得笨拙,因为一旦新类型被加到这种层次结构中,基类就必须更
新。可以用下面的多态工厂(polymorphic factory)来避免这种循环依赖。
Polymorphic factories
//: C10:ShapeFactory2.cpp
// Polymorphic Factory Methods.
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <stdexcept>
#include <cstddef>
#include "../purge.h"
using namespace std;

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

class ShapeFactory {
    virtual Shape* create() = 0;
    static map<string, ShapeFactory*> factories;
public:
    virtual ~ShapeFactory() {}
    friend class ShapeFactoryInitializer;
    class BadShapeCreation : public logic_error {
    public:
        BadShapeCreation(string type)
            : logic_error("Cannot create type " + type) {}
    };
    static Shape*
        createShape(const string& id) throw(BadShapeCreation) {
            if(factories.find(id) != factories.end())
                return factories[id]->create();
            else
                throw BadShapeCreation(id);
    }
};

// Define the static object:
map<string, ShapeFactory*> ShapeFactory::factories;

class Circle : public Shape {
    Circle() {} // Private constructor
    friend class ShapeFactoryInitializer;
    class Factory;
    friend class Factory;
    class Factory : public ShapeFactory {
    public:
        Shape* create() { return new Circle; }
        friend class ShapeFactoryInitializer;
    };
public:
    void draw() { cout << "Circle::draw" << endl; }
        void erase() { cout << "Circle::erase" << endl; }
        ~Circle() { cout << "Circle::~Circle" << endl; }
    };

    class Square : public Shape {
        Square() {}
        friend class ShapeFactoryInitializer;
        class Factory;
        friend class Factory;
        class Factory : public ShapeFactory {
        public:
            Shape* create() { return new Square; }
            friend class ShapeFactoryInitializer;
        };
    public:
        void draw() { cout << "Square::draw" << endl; }
            void erase() { cout << "Square::erase" << endl; }
            ~Square() { cout << "Square::~Square" << endl; }
        };

        // Singleton to initialize the ShapeFactory:
        class ShapeFactoryInitializer {
            static ShapeFactoryInitializer si;
            ShapeFactoryInitializer() {
                ShapeFactory::factories["Circle"]= new Circle::Factory;
                ShapeFactory::factories["Square"]= new Square::Factory;
            }
            ~ShapeFactoryInitializer() {
                map<string, ShapeFactory*>::iterator it =
                    ShapeFactory::factories.begin();
                while(it != ShapeFactory::factories.end())
                    delete it++->second;
            }
        };

        // Static member definition:
        ShapeFactoryInitializer ShapeFactoryInitializer::si;

        char* sl[] = { "Circle", "Square", "Square",
            "Circle", "Circle", "Circle", "Square" };

        int main() {
            vector<Shape*> shapes;
            try {
                for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++)
                    shapes.push_back(ShapeFactory::createShape(sl[i]));
            } catch(ShapeFactory::BadShapeCreation e) {
                cout << e.what() << endl;
                return EXIT_FAILURE;
            }
            for(size_t i = 0; i < shapes.size(); i++) {
                shapes[i]->draw();
                shapes[i]->erase();
            }
            purge(shapes);
        } ///:~
<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>

现在,工厂方法模式作为virtual create()出现在它自己的ShapeFactory类中。这是一个私
有成员函数,意味着不能直接调用它,但可认被覆盖。Shape的子类必须创建各自的ShapeFactory
子类,并且覆盖成员函数create()以创建其自身类型的对象。这些工厂得私有的,只能被主
工厂方法模式访问。采用这种方法,所有客户代码都必须通过工厂方法模式创建对象。
<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>
Abstract factories

抽象工厂模式看卢来和前面看到的工厂方法很相似,只是它使用若干工厂方法模式。每个工厂方法模式创建一个不同类型的对象。当创建一个工厂对象时,要决定将如何使用由那个工厂创建的所有对象。


//: C10:AbstractFactory.cpp
// A gaming environment.
#include <iostream>
using namespace std;

class Obstacle {
public:
    virtual void action() = 0;
};

class Player {
public:
    virtual void interactWith(Obstacle*) = 0;
};

class Kitty: public Player {
    virtual void interactWith(Obstacle* ob) {
        cout << "Kitty has encountered a ";
        ob->action();
    }
};

class KungFuGuy: public Player {
    virtual void interactWith(Obstacle* ob) {
        cout << "KungFuGuy now battles against a ";
        ob->action();
    }
};

class Puzzle: public Obstacle {
public:
    void action() { cout << "Puzzle" << endl; }
};

class NastyWeapon: public Obstacle {
public:
    void action() { cout << "NastyWeapon" << endl; }
};

// The abstract factory:
class GameElementFactory {
public:
    virtual Player* makePlayer() = 0;
    virtual Obstacle* makeObstacle() = 0;
};

// Concrete factories:
class KittiesAndPuzzles : public GameElementFactory {
public:
    virtual Player* makePlayer() { return new Kitty; }
    virtual Obstacle* makeObstacle() { return new Puzzle; }
};

// Other Concrete factories:
class KillAndDismember : public GameElementFactory {
public:
    virtual Player* makePlayer() { return new KungFuGuy; }
    virtual Obstacle* makeObstacle() {return new NastyWeapon;}
};

class GameEnvironment {
    GameElementFactory* gef;//环境
    Player* p;                //动作
    Obstacle* ob;        //角色
public:
    GameEnvironment(GameElementFactory* factory)
        : gef(factory), p(factory->makePlayer()),
        ob(factory->makeObstacle()) {}
    void play() { p->interactWith(ob); }
    ~GameEnvironment() {
        delete p;
        delete ob;
        delete gef;
    }
};

int main() {
    GameEnvironment
        g1(new KittiesAndPuzzles),
        g2(new KillAndDismember);
    g1.play();
    g2.play();
}
/* Output:
Kitty has encountered a Puzzle
KungFuGuy now battles against a NastyWeapon */ ///:~

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> 在此环境中,Player对象与Obstrcle对象交互,但是Player和Obstacle类型依赖具体的游戏。可以选择特定的GameElementFactory来决定游戏的类型,然后GameEnvironment控制游戏的设置和进行。在本例中,游戏的设置和进行很简单,但是那些动作(初始条件和状态变化在很大程度上决定了游戏的结果。在这里,GameEnvironment不是设计成继承的,即使这样做可能是有意义的。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics