【转】设计模式学习笔记(1)--抽象工厂
设计模式学习笔记(1)-抽象工厂
抽象工厂模式是GoF《设计模式》讲解的第一个模式,属于创建型模式。
说到创建型模式,就是为了创建类而衍生的一系列设计模式。在实际编程中,往往简单的new创建对象并不能满足我们的需要,一般来说创建对象遵循的GRASP(职责分配模式)有:
当一下条件之一为真是,B类负责创建A类。
B由A聚合或组合、B记录A、B直接使用A、B具有A的初始化数据
我们在开发程序中常面临一个状况:我们希望程序在不同的模式下有着不同的表现。这就是面向对象中所说的多态性,而实现多态性的途径就是面向接口而不是面向实现编程。接口是固定的,而实现是可以动态改变的。这便降低了模块之间的耦合度,使得程序易于维护。
今天学习的抽象工厂模式就是为了这个目标而建立的。
在抽象工厂模式中,我们将信息交给工厂,有工厂负责创建实现类,考虑到多态性,我们的工厂也是抽象的。举个例子:
如果我们要做一个游戏场景,这个场景有树(Tree)和天空(Sky)对象,Tree对象有color方法可以获得它的颜色,Sky有drop方法可以实现降水。即:
|
1
2
3
4
5
6
7
8
9
10
|
class Tree {public: virtual void color() = 0;};class Sky{public: virtual void drop() = 0;}; |
考虑到面向接口我们把这两个类定义为抽象类。然后写两个实现类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class TreeImpl : public Tree{public: void color() { cout << "The tree is green!" << endl; }};class SkyImpl : public Sky{public: void drop() { cout << "It rains" << endl; } }; |
好了,这样我们只要在主方法中调用
|
1
2
3
|
Tree* tree = new TreeImpl(); Sky* sky = new SkyImpl(); Tree->color();Sky->drop(); |
就可以实现这样一个场景了:绿色的树,天空下着雨。
可是这样一来场景就固化了,如果要做一个冬天的场景呢?冬天可不会下雨,树也不是绿色的。也许这样做是可以的:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class WinterTree : public Tree{public: void color() { cout << "The tree is black!" << endl; }};class SummerTree : public Tree{public: void color() { cout << "The tree is green!" << endl; }};class WinterSky : public Sky{public: void drop() { cout << "It snows" << endl; }};class SummerSky : public Sky{public: void drop() { cout << "It rains" << endl; } }; |
我们为每个场景各写了一个实现类,冬天有冬天的树,夏天有夏天的树。 在主方法中我们可以这样写: 冬天:
|
1
2
|
Tree* tree = new WinterTree (); Sky* sky = new WinterSky(); |
夏天:
|
1
2
|
Tree* tree = new SummerTree ();Sky* sky = new SummerSky(); |
看样子挺好,但是一旦要修改场景我们必须同时修改两处,如果该场景有成千上万个元素呢?比如说草、池塘?我们很自然地想到要有某个东西像下面这样就好了:
|
1
2
|
Tree* tree = SomeThing.createTree();Sky* sky = SomeThing.createSky(); |
这个SomeThing就是工厂。我们可以通过更改它实现整个场景的更改,这样便避免了在冬天出现天空下雪,树确实绿色的怪事。 这里有两个场景,所以要有两个工厂,考虑到程序应该依赖于抽象,还要有一个抽象工厂作为所有工厂的父类。
|
1
2
3
4
5
|
class Factory { public: virtual Tree* createTree() = 0; virtual Sky* createSky() = 0; }; |
这个工厂什么也不做,必须依靠子类来工作。这里是两个子类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class WinterFactory : public Factory {public: Tree* createTree() { return new WinterTree(); } Sky* createSky() { return new WinterSky(); }};class SummerFactory : public Factory {public: Tree* createTree() { return new SummerTree(); } Sky* createSky() { return new SummerSky(); }}; |
WinterFactory负责创建冬天场景的元素,SummerFactory负责创建夏天场景的元素。这样一来,主方法中只需这样写:
|
1
2
3
4
5
|
Factory* factory = new SummerFactory(); Tree* tree = factory->createTree();Sky* sky = factory->createSky();tree->color();sky->drop(); |
如果我们要修改成冬天的场景只需将第一行修改为:
|
1
|
Factory* factory = new WinterFactory(); |
即可。
全部代码只有这些,实现了一个最简单的抽象工厂。类图如下:
我们这里类与类之间的连接全部通过抽象类(接口)来完成,减少了系统的耦合度。
来看一下GoF所说的抽象工厂的适用性:
- 一个系统要独立与它的产品的创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当你提供一个产品类库,而只想显示它们的接口而不是实现时。
在我们的这个例子中,冬天和夏天是两个系列,而树和天空是两个产品。一个系列中的产品表现必须一致,因此采用抽象工厂模式是十分恰当的。
关系图:
这样以来就十分明朗了。
转自:http://lecoding.com/articles/51.html
posted on 2013-03-05 13:11 TheKingOfKingFish 阅读(128) 评论(0) 收藏 举报
浙公网安备 33010602011771号