cpp学习抽象工厂模式;
在学习抽象工厂模式之前,先来回忆一下上一节学习的工厂方法模式;
工厂方法模式,采用多态分离的方法,将简单工厂模式的工厂类解放为多个具体的子工厂, 从而继承简单工厂模式的优点,解决简单工厂模式的缺点;
工厂方法模式的缺点:在增加一个新产品的时候,需要增加一个产品类和一个具体的 子工厂,给系统带来额外的开销;同时,每个工厂生产一种产品,太过单一;
而抽象工厂模式,其实相对于工厂方法模式来说,就多了一点东西,所谓多的一点东西就是将同一品牌的产品都交给同一个工厂去生产。解决工厂方法模式的单一性;否则,如果每一个产品都需要一个工厂去生产的话,会需要非常多的子工厂类,造成类泛滥;
同一品牌的产品交给同一个工厂来生产的意思就是:比如所,现在生产的需要不仅仅是单一的Hair电视机,还要有Hair空调,Hair冰箱等,这些同一品牌的产品都交给HairFactory来生产,而这些属于同一品牌的产品有一个专业名词:一个产品族;
同时,同一类产品需要有一个共同的抽象基类,来提供共有的方法,比如:Hair空调,TCL空调,它们的父类都是Base空调类;这样的同一类产品也有一个专业名词的归属:一个产品等级;
下面简单画个图来理解一下族和等级的具体含义:
抽象工厂模式定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式;
重点内容模式结构:
抽象工厂,具体工厂,抽象产品,具体产品;
其实在这几种模式一步一步学过来,你会发现每一种模式都是在上一层模式的基础上进行了一些扩展,进而成为一种新的模式;
下面我用C++模拟一下抽象工厂模式,同样的一个问题还是没有解决,那就是Java的反射机制还没有找到合适的替代方案;
code:
#include<iostream>
using namespace std;
class TV
{
public:
//纯虚函数,抽象基类,公共方法;
virtual void play() = 0;
virtual ~TV() //注意将基类的析构函数设为虚函数
{
cout<<"~TV"<<endl;
}
};
//新增加的Air抽象产品类
class Air
{
public:
//纯虚函数,抽象基类,公共方法;
virtual void changeT() = 0; //改变温度
virtual ~Air() //注意将基类的析构函数设为虚函数
{
cout<<"~Air"<<endl;
}
};
//新增加的HairAir具体产品类
class HairAir:public Air
{
public:
void changeT() //改变温度
{
cout<<"Hair Air working!"<<endl;
}
~HairAir()
{
cout<<"~HairAir"<<endl;
}
};
class HairTv:public TV
{
public:
void play()
{
cout<<"Hair tv working!"<<endl;
}
~HairTv()
{
cout<<"~HairTv"<<endl;
}
};
class TCLTv:public TV
{
public:
void play()
{
cout<<"TCL tv working!"<<endl;
}
~TCLTv()
{
cout<<"~TCLTv"<<endl;
}
};
//新增加的TCLAir具体产品类
class TCLAir:public Air
{
public:
void changeT() //改变温度
{
cout<<"TCLAir Air working!"<<endl;
}
~TCLAir()
{
cout<<"~TCLAir"<<endl;
}
};
class BaseFactory
{
public:
//纯虚函数,抽象类;
virtual TV* TVproduct() = 0;
virtual Air* Airproduct() = 0;
virtual ~BaseFactory() //注意将基类的析构函数设为虚函数
{
cout<<"~BaseFactory"<<endl;
}
};
class SonHairFactory:public BaseFactory
{
public:
TV* TVproduct()
{
//Hair子工厂返回Hair产品对象;
//这里其实最好使用智能指针来维护这个对象,因为C++没有Java的垃圾回收机制
//容易造成内存泄漏;
cout<<"Hair tv being producted!"<<endl;
return new HairTv();
}
//Hair子工厂还要生产Hair 空调
Air* Airproduct()
{
cout<<"Hair Air being producted!"<<endl;
return new HairAir();
}
~SonHairFactory()
{
cout<<"~SonHairFactory"<<endl;
}
};
class SonTCLFactory:BaseFactory
{
public:
TV* TVproduct()
{
cout<<"TCL tv being producted!"<<endl;
return new TCLTv();
}
Air* Airproduct()
{
cout<<"TCL Air being producted!"<<endl;
return new TCLAir();
}
~SonTCLFactory()
{
cout<<"~SonTCLFactory"<<endl;
}
};
//我们直接以main函数来模拟客户端;
int main()
{
//注意,C++千万不要写成TV tv,会被笑的,抽象基类不可以不实例化;
TV* tv;
Air* air;
BaseFactory* factory;
//factory = ("Java反射机制得到的子工厂类型");
//C++的话现在只能将子工厂类名暴露出来了,暂时没找到合适的替代方法
factory = new SonHairFactory();
tv = factory->TVproduct(); //生产的对象传给tv指针,Java的话直接是对象;
tv->play();
air = factory->Airproduct();
air->changeT();
//释放空间; Java不需要,有垃圾回收机制;
delete(tv);
delete(air);
delete(factory);
system("pause");
return 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
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 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
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
结果:
看过代码,你就会发现,相比于工厂方法模式,抽象工厂方法模式就是为每个工厂增加了一个方法,产生一种新的产品;所以,如果每个子工厂如果只生产一种产品的话,抽象工厂模式就会退化为工厂方法模式;
抽象工厂模式的优点
- 抽象工厂模式隔离了具体类的生成,使客户端不需要知道什么被创建;这样的话更换一个工厂就很容易,只需要改变具体工厂的实例就可以;另外,抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用;
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象,这在跨平台的选择中有很大的作用,比如在windows和Linux下使用的Button和Text就不相同,此时我们需要所使用的Button和Text同属于一个平台,这样抽象工厂模式就起了很大的作用;
- 增加新的产品族很方便,只要增加一个具体产品类和一个具体工厂就可以;
抽象工厂模式的缺点
- 最大的缺点吧,就是增加一个产品等级的时候比较复杂,需要修改抽象产品类和抽象工厂类;比如,我现在要增加一个冰箱产品,那么就得在抽象产品类中增加一个关于冰箱的方法,也要在抽象工厂类中增加一个生产冰箱的公共方法,同时具体工厂类中也需要修改;这违背了开闭原则,所以,抽象工厂的开闭原则有了一定的倾斜性,在增加一个族产品时,符合开闭原则,而增加一个产品等级的话,既不符合开闭原则;
什么是开闭原则
开闭原则要求系统对扩展,对修改封闭,通过扩展以达到增强其功能的目的。
抽象该工厂的应用
- Java语言中的AWT包就是用了抽象工厂模式,Swing包应该也支持;
- 很多软件的系统支持桌面主题的更换,比如你的手机,更换桌面主题一般都会把按钮啊图标啊之类的全部换为一套个性化的主题,这就是抽象工厂模式的应用;