GOF:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
类图:
观察类图,关键就在于左边,即AbstractFactory和它的两个子类。想要理解这个模式,我们可以真的将它看作一个工厂。对于生产家电的工厂,一般要生产电视和洗衣机,但是在美国的家电工厂生产的是等离子电视和全自动洗衣机,在非洲的家电工厂生产的是CRT彩电和半自动洗衣机。把这个例子转换成类似上面的类图就如下:
这时,如果想要开工厂,就能从彩电工厂生产标准知道彩电工厂能生产电视和洗衣机,然后根据你在哪个国家来具体决定彩电工厂的类型。
AbstractFactory一般是抽象类(但不是绝对的),它定义了必需的接口,而具体接口的实现放到了子类。用户只需知道Factory中有什么接口就行了,剩下就交给多态吧(在设计模式中,很多巧妙的地方就是靠多态实现的)。
比如:一群学生要去参观家电工厂的生产过程,则代码如下:
void StudentVisit(AbstractFactory& factory) { factory.MakeTV(); factory.MakeWasher(); } int main() { USAFactory factory; StudentVisit(factory); return 0; }
这里实际传入的参数是美国家电工厂,则实际调用的是美国家电工厂的MakeTV()和MakeWasher()。
适用性:
优点 + 缺点:
最后以一个创建游戏场景的例子结束,该游戏场景会产生地形,光源,植被。
类图:
代码:
先看看Product,即类图右边的类:
地形类:
class Terrain { public: virtual string GetType() const = 0; }; class DesertTerrain : public Terrain { public: DesertTerrain() { m_type = "Desert"; } string GetType() const { return m_type; } private: string m_type; }; class MountainTerrain : public Terrain { public: MountainTerrain() { m_type = "Mountain"; } string GetType() const { return m_type; } private: string m_type; };
光源类:
class Light { public: virtual string GetType() const = 0; }; class SpotLight : public Light{ public: SpotLight() { m_type = "Spot Light"; } string GetType() const { return m_type; } private: string m_type; }; class DirectionLight : public Light { public: DirectionLight() { m_type = "Direction Light"; } string GetType() const { return m_type; } private: string m_type; };
植被类:
class Plant { public: virtual string GetType() const = 0; }; class TreePlant : public Plant { public: TreePlant() { m_type = "Tree"; } string GetType() const { return m_type; } private: string m_type; }; class CactusPlant : public Plant { public: CactusPlant() { m_type = "Cactus"; } string GetType() const { return m_type; } private: string m_type; };
以下就看工厂类:
class GameSceneFactory { public: virtual Terrain* MakeTerrain() const = 0; virtual Light* MakeLight() const = 0; virtual Plant* MakePlant() const = 0; }; class DesertSceneFactory : public GameSceneFactory { public: Terrain* MakeTerrain() const { return new DesertTerrain(); } Light* MakeLight() const { return new DirectionLight(); } Plant* MakePlant() const { return new CactusPlant(); } }; class MountainSceneFactory : public GameSceneFactory { public: Terrain* MakeTerrain() const { return new MountainTerrain(); } Light* MakeLight() const { return new SpotLight(); } Plant* MakePlant() const { return new TreePlant(); } };
以下就是具体的使用:
class Game { public: void createScene(GameSceneFactory& factory) { m_terrain = factory.MakeTerrain(); m_light = factory.MakeLight(); m_plant = factory.MakePlant(); print(); } void print() { cout << "------Game Scene------" << endl; cout << "Terrain: " << m_terrain->GetType() << endl; cout << "Light: " << m_light->GetType() << endl; cout << "Plant: " << m_plant->GetType() << endl; } private: Terrain* m_terrain; Light* m_light; Plant* m_plant; }; int main() { Game game; MountainSceneFactory factory; game.createScene(factory); }
结果:
小结:抽象工厂模式是一个比较常用的模式,需要好好掌握。利用真实生活中的工厂就比较好理解该模式的运作,但真正要掌握还得在日常编码中的适当场合使用。