对象设计模式
工厂方法
例如在在一个类A中, 例如我需要在运行的过程中创建令一个类的对象。但是如果直接NEW对象 B,那么这个B就和这个A产生了强依赖,A在编译的时候就依赖B了
例如如下代码:
#include <iostream>
#include <map>
class splitter{
public:
virtual void split() = 0;课程
};
class TxtSplitter : public splitter{
void split() override{
std::cout << " 1" << std::endl;
}
};
class MusicSplitter : public splitter{
void split() override{
std::cout << "2" << std::endl;
}
};
class Button {
public:
Button(){
}
void click(){
splitter* spl = new MusicSplitter();
spl ->split();
delete(spl);
}
private:
};
int main() {
auto button = Button();
button.click();
}
例如我有一个类Button, 在用户点击按钮之后会调用click方法,之后这个函数需要将用户选择的内容分解为数个部分。用户选择的内容可能是音乐,文件等。 所以很容易想到将 split
抽象出一个方法, 例如上述代码中的 class splitter
。 TxtSplitter 和 MusicSplitter分别实现文件分割和音乐的分割。之后在 class Button 在是实例化相应的对象, 这样子看似可以,但实际上 Button 和 MusicSplitter 产生了强依赖。在编的编译的时候编译TxtSplitter 必须 需要MusicSplitter。
如何改进呢? 看下列的代码
class ISplitterFactory{
public:
virtual ISplitter* CreateSplitterFactory() = 0;
};
class TxtSplitterFactory : public ISplitterFactory{
public:
ISplitter* CreateSplitterFactory() override{
return new MusicSplitter();
}
};
用一个抽象类将里面放一个方法用于去生成ISplitter对象。
之后的buottn的代码可以写成下面的样子:
class Button1 {ISplitterFactory
public:
Button1(ISplitterFactory *sql_factory)
: SqlFactory_(sql_factory)
{
}
void click(){
//千万不可以写成这样子,如果写成这样子实际上又和上面一样了。
//ISplitter* spl = TxtSplitterFactory().CreateSplitterFactory();
ISplitter* spl = SqlFactory_->CreateSplitterFactory();
spl ->split();
delete(spl);
}
private:
ISplitterFactory* SqlFactory_;
};
这样子,虽然最终编译的时候为们还是需要TxtSplitterFactory,但Button1实际上和前者已经没有强依赖了。
外部的函数可以写成这样子
int main() {
// auto button = Button();
// button.click();
TxtSplitterFactory* factory = new TxtSplitterFactory(); //通过这个方法就可以将初始化的时间延续到运行时;
Button1 a(factory);
a.click();
}
上面的情况比较简单,只有一个步骤,但如果是一个很复杂的过程,例如:数据库的操作, 连接, 读取,解析一系列步骤,而每个步骤都需要一个新的对象。 那么就相当于每一个对象都需要一个工厂了,上面的三个步骤就相当于三个对象。 例如:
class SqlConnection : public IDbConnection{
public:
void connection() override{
std::cout << "connection" << std::endl;
}
};
class SqlCommand : public IDbCommand{
void execute() override{
std::cout << "execute" << std::endl;
}
};
class SqlReader : public IDataReader{
void reader() override{
std::cout << "read" << std::endl;
}
};
加入要支持 influxdb 那么就需要在写三个。
但是这样有一个问题SqlConnection对象的结果只能用SqlCommand处理。 而不能用influxdbCommand。 这样子我们可以写的更好一点
class IDBFactory{
public:
virtual IDbConnection* CreateDbConnection() =0;
virtual IDbCommand* CreateDbCommand() = 0;
virtual IDataReader* CreateDbReader() = 0;
};
class EmployDao{
IDBFactory* dbFactory;
public:
std::vector<std::string> GetEmploy(){
IDbConnection* connection = dbFactory->CreateDbConnection();
//...
IDbCommand* cmd = dbFactory->CreateDbCommand();
//...
IDataReader* reader = dbFactory->CreateDbReader();
}
};
一个这样的工厂,这样子就将同一类的封装起来了。 通过一个工厂生成多个不同的对象。
proptype 原型对象
如果一个类有很多中间状态,创建之后如果要经过一两个阶段之后才可以使用,那么对于这样的类可以使用原型模式, 通过clone的方法直接将这个对象拷贝出来
例如:
class MainForm {
private:
ISplitter1* prototype_;
public:
MainForm(ISplitter1* prototype){
this->prototype_ = prototype;
}
void Button_click(){
ISplitter1* splitter = prototype_->clone();
splitter->split();
delete(splitter);
}
};
上面的类中的 ISplitter1* prototype_; 是专门用于创建对象用的,在这个设计模式中它里面的内容不应该被改变。如果或改变了就变味道了
builder 构建器模式
当面对复杂对象的创建工作,通常各自部分的子对象用一定的算法构成, 但是将他们组合在一起的算法却相对稳定
那么在父类中可以封装算法函数。在子类中实现各个步骤例如:
class House {
public:
void init(){
BuildPart1();
for (int i = 0; i < 4; i++) {
BuildPart2();
}
for (int i = 0; i < 2; i++){
BuildPart3();
}
}
~House(){};
protected:
virtual void BuildPart1() = 0;
virtual void BuildPart2() = 0;
virtual void BuildPart3() = 0;
};
class BigHour : public House{
virtual void BuildPart1(){
std::cout << "1" << std::endl;
}
virtual void BuildPart2(){
std::cout << "2" << std::endl;
}
virtual void BuildPart3(){
std::cout << "3" << std::endl;
}
};
int main(){
House* p = new BigHour;
p->init();
}
在构建BigHour的时候是,我们只需要重写三个虚函数即可。
class Hous{
public:
std::string name;
};
class HouseBuilder {
public:
HouseBuilder(Hous* p){
pHous_ = p;
}
Hous* GetResult(){
return pHous_;
}
virtual void BuildPart1() = 0;
virtual void BuildPart2() = 0;
virtual void BuildPart3() = 0;
protected:
Hous* pHous_;
};
class StoneHouseBuilder : public HouseBuilder{
public:
StoneHouseBuilder(Hous* p)
:HouseBuilder(p)
{
}
virtual void BuildPart1(){
pHous_->name.append("a");
}
virtual void BuildPart2(){
pHous_->name.append("b");
}
virtual void BuildPart3(){
pHous_->name.append("c");
}
private:
};
class HourDirector{
HouseBuilder* pHouseBuilder;
public:
HourDirector(HouseBuilder* p){
pHouseBuilder = p;
}
Hous* Construct(){
pHouseBuilder->BuildPart1();
for (int i = 0; i < 4; ++i) {
pHouseBuilder->BuildPart2();
}
pHouseBuilder->BuildPart3();
return pHouseBuilder->GetResult();
}
};
int main(){
Hous a;
StoneHouseBuilder builder(&a);
HourDirector director(&builder);
std::cout << director.Construct()->name << std::endl;
}
还有一个最终版本的,将房子,方法,构建步骤都进行区分的方法:
Hous 用于这个对象的上下文,HouseBuilder是每个的步骤,HourDirector用于封装步骤