相信我们基本都买过台式电脑吧。我们应该不会去买主板,CPU,内存等等子部件回家,然后自己组装成台式机。当然,也不排除某些发烧友这样做。但是对于多数人来说,我们只需要对老板说,我需要一台联想的或者惠普的电脑,老板组装好给我们就OK了。我们买车也是这样的,只是买一台车回家,而不是买回一堆的发动机等等零件。
上面的例子,抽象一下,就是建造者模式。
建造者模式是创建模式中最复杂的,这个复杂指的是类的结构和实现会复杂一些。它的使用场景不复杂,很好理解。就是创建复杂对象。什么是复杂对象呢,比如对象里面包含很多子部件,或者创建过程中每个子部件的创建顺序需要严格遵守。这时候,对于类的设计者就要封装这些复杂性,为类的使用者提供简便的接口即可,而不用理会对象是何创建的。
很多人包括我自己也问,这个场景使用工厂方法模式可以吗?答案是可以,但是这样一来工厂方法里面的接口就需要处理很多事情,包括new多个子组件,控制创建的顺序。而使用建造者模式则会优美很多。这个反映了设计模式的使用原则,那就是"合适的才是最好的"。
至于类图,网络上很多,这里就偷懒不画了,通过代码和例子来学习。通过调试学习下代码,看看类图,改改代码,才能更好理解模式。
上面的例子,抽象一下,就是建造者模式。
建造者模式是创建模式中最复杂的,这个复杂指的是类的结构和实现会复杂一些。它的使用场景不复杂,很好理解。就是创建复杂对象。什么是复杂对象呢,比如对象里面包含很多子部件,或者创建过程中每个子部件的创建顺序需要严格遵守。这时候,对于类的设计者就要封装这些复杂性,为类的使用者提供简便的接口即可,而不用理会对象是何创建的。
很多人包括我自己也问,这个场景使用工厂方法模式可以吗?答案是可以,但是这样一来工厂方法里面的接口就需要处理很多事情,包括new多个子组件,控制创建的顺序。而使用建造者模式则会优美很多。这个反映了设计模式的使用原则,那就是"合适的才是最好的"。
至于类图,网络上很多,这里就偷懒不画了,通过代码和例子来学习。通过调试学习下代码,看看类图,改改代码,才能更好理解模式。
首先是测试结果:
然后是完整C++代码:
/* 产品类,这里用"电脑类"来说明 */
class Computer
{
public:
virtual void SetCPU() = 0; //CPU
virtual void SetRAM() = 0; //内存
virtual void SetDisk() = 0; //硬盘
virtual void SetCDROM() = 0;
virtual void Run() = 0;
virtual int GetRAMCount(){return m_CountOfRAM;}
virtual int GetDiskCount(){return m_CountOfDisk;}
protected:
int m_CountOfRAM; //内存条数量
int m_CountOfDisk; //硬盘数量
};
class IBMComputer : public Computer
{
public:
IBMComputer(int RAMCount,int DiskCount)
{
m_CountOfDisk = DiskCount;
m_CountOfRAM = RAMCount;
}
virtual void SetCPU()
{
printf("IBMComputer::SetCPU...\r\n");
}
virtual void SetRAM()
{
printf("IBMComputer::SetRAM...\r\n");
}
virtual void SetDisk()
{
printf("IBMComputer::SetDisk...\r\n");
}
virtual void SetCDROM()
{
printf("IBMComputer::SetCDROM...\r\n");
}
virtual void Run()
{
printf("IBMComputer::Runing...\r\n");
}
};
class LenovoComputer : public Computer
{
public:
LenovoComputer(int RAMCount,int DiskCount)
{
m_CountOfDisk = DiskCount;
m_CountOfRAM = RAMCount;
}
virtual void SetCPU()
{
printf("LenovoComputer::SetCPU...\r\n");
}
virtual void SetRAM()
{
printf("LenovoComputer::SetRAM...\r\n");
}
virtual void SetDisk()
{
printf("LenovoComputer::SetDisk...\r\n");
}
virtual void SetCDROM()
{
printf("LenovoComputer::SetCDROM...\r\n");
}
virtual void Run()
{
printf("LenovoComputer::Runing...\r\n");
}
};
class Builder
{
public:
virtual void BuildCPU() = 0;
virtual void BuildRAM() = 0;
virtual void BuildDisk() = 0;
virtual void BuildCDROM() = 0;
virtual Computer* GetComputer() = 0;
virtual ~Builder()
{
if(m_pComputer)
{
delete []m_pComputer;
m_pComputer = NULL;
}
}
protected:
Computer* m_pComputer;
};
class IBMBuiler : public Builder
{
public:
IBMBuiler()
{
m_pComputer = new IBMComputer(2,1);
printf("IBM 电脑,需要2个内存条,1个硬盘\r\n");
}
virtual void BuildCPU()
{
m_pComputer->SetCPU();
}
virtual void BuildRAM()
{
m_pComputer->SetRAM();
}
virtual void BuildDisk()
{
m_pComputer->SetDisk();
}
virtual void BuildCDROM()
{
m_pComputer->SetCDROM();
}
virtual Computer* GetComputer()
{
return m_pComputer;
}
};
class LenovoBuilder : public Builder
{
public:
LenovoBuilder()
{
m_pComputer = new LenovoComputer(1,2);
printf("Lenovo 电脑,需要1个内存条,2个硬盘\r\n");
}
virtual void BuildCPU()
{
m_pComputer->SetCPU();
}
virtual void BuildRAM()
{
m_pComputer->SetRAM();
}
virtual void BuildDisk()
{
m_pComputer->SetDisk();
}
virtual void BuildCDROM()
{
m_pComputer->SetCDROM();
}
virtual Computer* GetComputer()
{
return m_pComputer;
}
};
class Director
{
public:
Director(Builder* pBuilder)
{
m_pBuilder = pBuilder;
}
void BuildComputer()
{
m_pBuilder->BuildCPU();
for(int i=0;i<m_pBuilder->GetComputer()->GetRAMCount();i++)
{
m_pBuilder->BuildRAM();
}
for(int i=0;i<m_pBuilder->GetComputer()->GetDiskCount();i++)
{
m_pBuilder->BuildDisk();
}
m_pBuilder->BuildCDROM();
}
private:
Builder* m_pBuilder;
};
void TestBuilder()
{
Builder* b1 = new IBMBuiler();
Director* director1 = new Director(b1);
director1->BuildComputer();
b1->GetComputer()->Run();
Builder* b2 = new LenovoBuilder();
Director* director2 = new Director(b2);
director2->BuildComputer();
b2->GetComputer()->Run();
delete b1;
delete b2;
delete director1;
delete director2;
}