动机
- 抽象框架感知抽象类,抽象框架必须实例化一个具体类,但抽象框架不知道哪个类要被实例化。
- 绕开常规创建对象方法new,提供一种”封装机制”来避免客户程序和具体对象的紧耦合
定义
- 意图定义一个用于创建对象的接口,让子类决定实例化哪个类。
- 使一个类的实例化延迟到其子类。
引出问题
一个用于文件分割的程序
变化在于对于不同的文件有不同的分割操作
以下代码中忽略了实际工程中的参数细节
1
2
3
4
5
6
7
8
9
10
11
12class MainForm : public Form
{
public:
void Button1_Click(){
ISplitter * splitter1= new BinarySplitter();//依赖具体类
splitter1->split();
}
void Button2_Click(){
ISplitter * splitter2= new ImageSplitter();//依赖具体类
splitter1->split();
}
};1
2
3
4
5
6class Splitter{
protected:
vitural split() = 0;
~Splitter() {}
};1
2
3
4
5
6
7
8
9class BinarySplitter : public Splitter{
protected:
split();
};
class ImageSplitter : public Splitter{
protected:
split();
};该例子中
MainForm作为高层模块中依赖于底层模块的变化,违背了依赖倒置原则具体讲就是
MainForm作为抽象功能却依赖的具体的对象BinarySplitter和ImageSplitter
思路:隐藏变化(具体实现)
MainForm中必须要用到一个实现,但我们又要隐藏他的实现细节- 利用虚函数的多态性,使用一个抽象接口来实例化具体类
1
2
3
4
5
6
7
8
9class MainForm : public Form
{
public:
void Button_Click(){
SplitterFactory sf;
ISplitter * splitter = sf.CreateSplitter();//依赖具体类
splitter->split();
}
};1
2
3
4
5
6class SplitterFactory{
public:
ISplitter * CreateSplitter(){
return new BinarySplitter(); //or new ImageSplitter()
}
}; - 这一版代码,虽然看似在
MainForm隐藏了具体实现,但他依赖的SplitterFactory类还是要依赖具体实现,所以还需要进一步改造
将实现放在未来
- 将
SplitterFactory::CreateSplitter定义为纯虚函数1
2
3
4
5
6
7
8
9class MainForm : public Form
{
public:
void Button_Click(){
SplitterFactory *sf;
ISplitter * splitter = sf->CreateSplitter();
splitter->split();
}
};1
2
3
4
5class SplitterFactory{
public:
virtual ISplitter * CreateSplitter() = 0;
~SplitterFactory(){}
};1
2
3
4
5
6
7
8
9
10
11
12
13class BinarySplitterFactory : SplitterFactory{
public:
ISplitter * CreateSplitter() {
return new BinarySplitter();
}
};
class ImageSplitterFactory : SplitterFactory{
public:
ISplitter * CreateSplitter() {
return new ImageSplitter();
}
}; - 此时,
MainForm就完全不依赖具体的实现了,所有的方法都是抽象的 - 那么新的问题来了,
MainForm中的sf如何初始化呢
最终的版本
- 通常是将
sf作为MainForm的成员变量,因为他可能被多次使用 - 并通过
MainForm的构造函数初始化1
2
3
4
5
6
7
8
9
10class MainForm : public Form
{
SplitterFactory *sf;
public:
MainForm(SplitterFactory *sf) : sf(sf) {}
void Button_Click(){
ISplitter * splitter = sf->CreateSplitter();
splitter->split();
}
};1
2
3
4
5class SplitterFactory{
public:
virtual ISplitter * CreateSplitter() = 0;
~SplitterFactory(){}
};1
2
3
4
5
6
7
8
9
10
11
12
13class BinarySplitterFactory : SplitterFactory{
public:
ISplitter * CreateSplitter() {
return new BinarySplitter();
}
};
class ImageSplitterFactory : SplitterFactory{
public:
ISplitter * CreateSplitter() {
return new ImageSplitter();
}
};
一点疑问
- 既然
MainForm可以传入多态指针,那为什么不直接传入ISplitter*呢,何必绕一圈? - 猜想可能是sf中未来可能集成各种不同对象的create
总结
- 类图
以上。