对象创建模式
通过对象创建模式绕开new,来避免对象创建过程中所导致的紧耦合(依赖具体类)从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
- 工厂方法Factory Method
- 抽象工厂Abstract Factory
- 原型模式Prototype
- 构造器Builder
1.工厂方法Factory Method
动机: 在软件系统中经常面临着创建对象的工作,由于需求的变化,需要创建的对象的具体类型经常变化
如何应对这种变化?如何绕过常规的对象创建方法 new,提供一种封装机制来避免客户程序和这种具体对象创建工作的紧耦合?
//文件分割器
//平台实现
class MainForm{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
FileSplitter* splitter = new FileSplitter(filePath, number);//具体的类 当需求需要改变时就需要更改
//面向接口的编程 一个对象的类型往往声明称一个抽象类/接口 以应对未来需求的变化
splitter->split();
}
};
//分割操作
class FileSplitter{
public:
void split(){
//.....
}
};
//需求改变:一开始仅支持二进制形式的分割 支持文本文件的分割/视频文件的分割等
//依赖倒置原则:应该依赖于抽象 不应该依赖抽象细节
//平台实现
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
ISplitter * splitter = new BinarySplitter();//虽然ISplitter是抽象的 但是其后实例化的是一个具体的类型 还是编译时的依赖
//抽象基类/接口是不能创建new的
//=左右依赖抽象 但是右边依赖具体
splitter->split();
}
};
//分割操作
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
//平台 mainform只依赖工厂基类和抽象类
class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:
MainForm(SplitterFactory* factory) : factory(factory){}
void Button1_Click(){
//ISplitter * splitter = new BinarySplitter();//依赖具体类
// SplitterFactory factory;//factory依赖BinarySplitter 本质上还是编译时依赖
// ISplitter* splitter = factory.CreateSplitter();
ISplitter* splitter = factory->CreateSplitter();//多态new
splitter->split();
}
};
//工厂基类
class SplitterFactory{
public:
//虚函数 运行时依赖 延迟效果
virtual ISplitter* CreateSplitter() = 0;
// ISplitter CreateSplitter(){
// //return new ISplitter(...);//error 抽象基类
// return new BinarySplitter();
// }
virtual ~SplitterFactory(){}
};
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//具体类
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
//针对具体类创建具体工厂 具体工厂
class BinarySplitterFactory : public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
retrun new BinarySplitter();
}
};
class TxtSplitterFactory : public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
retrun new TxtSplitter();
}
};
class PictureSplitterFactory : public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
retrun new PictureSplitter();
}
};
class VideoSplitterFactory : public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
retrun new VideoSplitter();
}
};
设计模式/面向对象的松耦合设计并不是将变化消灭掉,而是将变化赶到一个局部的地方
eg:变化是一只猫 将猫关在笼子里要比让猫在房子里跳来跳去要好得多
模式定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦 手段:虚函数)到子类
mainform只依赖红色的
- product——>Isplitter
- concreteProduct——>具体的BinarySplitter等
- creator——>工厂基类
- concreteProduct——>具体工厂
要点总结:
- Factory Method模式用于隔离类对象的使用者和具体类型间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱
- Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(非更改)的策略,较好地解决了这种紧耦合关系
- Factory Method模式解决单个对象的需求变化,缺点在于要求创建方法/参数相同
2.抽象工厂Abstract Factory
动机: 在软件系统中,经常面临着一系列互相依赖的对象的创建工作,同时,由于需求的变化,往往存在更多系列对象的创建工作
如何应对这种变化?如何绕开常规的对象创建方法new,提供一种封装机制来避免客户程序和这种多系列具体对象创建工作的紧耦合?
//工厂模式解决方法
//写一个数据访问层
class EmployeeDAO{
public:
vector<EmployeeDO> GetEmployees(){
//数据库链接
SqlConnection* connection =
new SqlConnection();
connection->ConnectionString = "...";
//数据库命令
SqlCommand* command =
new SqlCommand();
command->CommandText="...";
command->SetConnection(connection);
//数据库数据读
SqlDataReader* reader = command->ExecuteReader();
while (reader->Read()){
}
}
};
//上述的数据库是mysql的 如果数据库更改就会引起大量变化
//写一个数据访问层
//面向接口编程 工厂模式解决
class IDBConnection{
};
class IDBConnectionFactory{
public:
virtual IDBConnection* CreateDBConnection() = 0;
};
class IDBCommand{
};
class IDBCommandFactory{
public:
virtual IDBCommand* CreateDBCommand() = 0;
};
class IDBDateReader{
};
class IDBDateReaderFactory{
public:
virtual IDBDateReader* CreateDateReader() = 0;
};
//支持sql server
//具体类
class SqlConnection : public IDBConnection{
};
//具体工厂
class SqlConnectionFactory : public IDConnectionFactory{
virtual IDBConnection* CreateDBConnection(){
return new SqlConnection();
}
};
class SqlCommand : public IDBCommand{
};
class SqlCommandFactory : public IDBCommandFactory{
virtual IDBCommand* CreateDBCommand(){
return new SqlCommand();
}
};
class SqlDateReader : public IDBDateReader{
};
class SqlDateReaderFactory : public IDBDateReaderFactory{
virtual IDBDateReader* CreateDBDateReader(){
return new SqlDateReader();
}
};
//支持Oracle
class OracleConnection : public IDBConnection{
};
class OracleConnectionFactory : public IDConnectionFactory{
virtual IDBConnection* CreateDBConnection(){
return new OracleConnection();
}
};
class OracleCommand : public IDBCommand{
};
class OracleCommandFactory : public IDBCommandFactory{
virtual IDBCommand* CreateDBCommand(){
return new OracleCommand();
}
};
class OracleDateReader : public IDBDateReader{
};
class OracleDateReaderFactory : public IDBDateReaderFactory{
virtual IDBDateReader* CreateDBDateReader(){
return new OracleDateReader();
}
};
class EmployeeDAO{
//构造函数中的初始化
//下面三个对象必须传统一系列的 是mysql都是mysql 是oracle都是Oracle
IDBConnectionFactory* dbConnectionFactory;
IDBCommandFactory* dbCommandFactory;
IDBDateReaderFactory* dbDateReaderFactory;
public:
vector<EmployeeDO> GetEmployees(){
//数据库链接
IDBConnection* connection = dbConnectionFactory->CreateDBConnection();
connection->ConnectionString = "...";
//数据库命令
IDBCommand* command = dbCommandFactory->CreateDBCommand();
command->CommandText="...";
command->SetConnection(connection);//关联性
//数据库数据读
IDBDataReader* reader = dbDateReaderFactory->CreateDateReader();
while (reader->Read()){
}
}
};
//缺点:工厂对象必须是同系列的 是mysql都是mysql 是oracle都是Oracle
//写一个数据访问层
//面向接口编程
//抽象工厂方法(家族工厂更好理解)
class IDBConnection{
};
class IDBCommand{
};
class IDBDateReader{
};
class IDBFactory{
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDBDateReader* CreateDateReader() = 0;
};
//支持sql server
//具体类
class SqlConnection : public IDBConnection{
};
class SqlCommand : public IDBCommand{
};
class SqlDateReader : public IDBDateReader{
};
//具体工厂
class SqlFactory : public IDBFactory{
virtual IDBConnection* CreateDBConnection(){
return new SqlConnection();
}
virtual IDBCommand* CreateDBCommand(){
return new SqlCommand();
virtual IDBDateReader* CreateDBDateReader(){
return new SqlDateReader();
}
};
//支持Oracle
class OracleConnection : public IDBConnection{
};
class OracleCommand : public IDBCommand{
};
class OracleDateReader : public IDBDateReader{
};
class OracleFactory : public IDBFactory{
virtual IDBConnection* CreateDBConnection(){
return new OracleConnection();
}
virtual IDBCommand* CreateDBCommand(){
return new OracleCommand();
}
virtual IDBDateReader* CreateDBDateReader(){
return new OracleDateReader();
}
};
class EmployeeDAO{
//构造时初始化
IDBFactory* dbFactory;//保证了关联性
public:
vector<EmployeeDO> GetEmployees(){
//数据库链接
IDBConnection* connection = dbFactory->CreateDBConnection();
connection->ConnectionString = "...";
//数据库命令
IDBCommand* command = dbFactory->CreateDBCommand();
command->CommandText="...";
command->SetConnection(connection);
//数据库数据读
IDBDataReader* reader = dbFactory->CreateDateReader();
while (reader->Read()){
}
}
};
模式定义: 提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类
- AbstractFactory->IDBFactory
- ConcreteFactory->SqlFactory/OracleFactory
- AbstractProduct->IDBConnection/IDBCommand/IDBDateReader
- Product->Sql/OracleConnection、Sql/OracleCommand、Sql/OracleDateReader
要点总结:
- 如果没有应对多系列对象构建的需求变化,则没有必要使用Abstract Factory模式,只需工厂模式就可以了
- 系列对象指的是在某一特定系列下的对象之间有依赖或作用的关系 不同系列的对象之间不能相互依赖
- Abstract Factory模式主要在于应对新系列的需求变动 其缺点在于难以对应新对象的需求变动
设计模式解决稳定中有变化 将变化局限在一定的范围
3.原型模式Prototype
动机: 在软件系统中,经常面临某些结构复杂的对象的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较一致的接口
如何应对这种变化?如何向客户程序(使用这些对象的程序)隔离出这些易变对象,从而使得依赖这些易变对象的客户程序不随着需求改变而改变?
//工厂模式 文件分割器
//界面
class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:
MainForm(SplitterFactory* factory){
this->factory=factory;
}
void Button1_Click(){
ISplitter * splitter=
factory->CreateSplitter(); //多态new
splitter->split();
}
};
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0;
virtual ~SplitterFactory(){}
};
//具体类
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new BinarySplitter();
}
};
class TxtSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new TxtSplitter();
}
};
class PictureSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new PictureSplitter();
}
};
class VideoSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new VideoSplitter();
}
};
//原型模式 将产品抽象类和工厂抽象类合并
//界面
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype = prototype;
}
void Button1_Click(){
//prototype->split();//不能直接使用原型对象 仅供克隆
ISplitter * splitter = prototype->clone();//克隆原型
splitter->split();
}
};
//将抽象类和工厂基类合并
class ISplitter{
public:
virtual void split()=0;
virtual ISplitter* clone()=0;//通过clone自己来创建对象
virtual ~ISplitter(){}
};
//具体类
class BinarySplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new BinarySplitter(*this);
}
};
class TxtSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new TxtSplitter(*this);
}
};
class PictureSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new PictureSplitter(*this);
}
};
class VideoSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new VideoSplitter(*this);
}
};
//为什么要合并?解决了什么问题?跟工厂模式最大的区别?
//某些复杂的对象 初始的对象状态我不想用 想用特定状态的对象 只需要先确定一个特定状态的对象然后clone即可
模型定义: 使用原型实例指定创建对象的种类,然后通过copy这些原型来创建新的对象
- Prototype->ISplitter
- ConcretePrototype->BinarySplitter/VedioSplitter…
- Client->Mainform
要点总结:
- Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些易变类拥有稳定的接口
- Prototype模式对于如何创建易变类的实体对象采用原型克隆的方法来做,它使得我们可以非常灵活地动态创建拥有某些稳定接口地新对象——所需工作仅仅是注册一个新类地对象(原型)然后任何需要时clone即可
- Prototype模式中地clone方法可以利用某些框架中额序列化来实现深copy(c++使用copy构造函数即可)
4.构造器Builder
动机: 在软件系统中,有时候面临着一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂的对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法相对稳定
如何应对这种变化?如何提供一种封装机制来隔离出复杂对象的各个部分的变化,从而保持系统中的稳定构建算法不随着需求改变而改变?
//建房子需要固定几个流程 但不同的房子具体的流程有差别
//构建的流程是稳定的
//c++构造函数调用虚函数是静态绑定 不是动态绑定 不能实现多态 所以下面的Init不能改为构造函数
class House{
public:
//同一个构建过程
void Init(){
this->BuildPart1();
for(int i = 0; i < 4; i++){
this->BuildPart2();
}
bool flag = this->BuildPart3();
if(flag) this->BuildPart4();
this->BuildPart5();
}
protected:
virtual void BuildPart1()=0;
virtual void BuildPart2()=0;
virtual void BuildPart3()=0;
virtual void BuildPart4()=0;
virtual void BuildPart5()=0;
};
class StoneHouse() : public House{
protected:
virtual void BuildPart1(){}
virtual void BuildPart2(){}
virtual void BuildPart3(){}
virtual void BuildPart4(){}
virtual void BuildPart5(){}
};
class AdobeHouse() : public House{
protected:
virtual void BuildPart1(){}
virtual void BuildPart2(){}
virtual void BuildPart3(){}
virtual void BuildPart4(){}
virtual void BuildPart5(){}
};
//
//将对象的表示和流程分离
//表示
class House{
//....
};
//构建 专门负责构建
class HouseBuilder {
public:
House* GetResult(){
return pHouse;
}
virtual ~HouseBuilder(){}
protected:
House* pHouse;
virtual void BuildPart1()=0;
virtual void BuildPart2()=0;
virtual void BuildPart3()=0;
virtual void BuildPart4()=0;
virtual void BuildPart5()=0;
};
class StoneHouse: public House{
};
class StoneHouseBuilder: public HouseBuilder{
protected:
virtual void BuildPart1(){
//pHouse->Part1 = ...;
}
virtual void BuildPart2(){
}
virtual void BuildPart3(){
}
virtual void BuildPart4(){
}
virtual void BuildPart5(){
}
};
//将流程单独分离
class HouseDirector{
public:
HouseBuilder* pHouseBuilder;
HouseDirector(HouseBuilder* pHouseBuilder){
this->pHouseBuilder=pHouseBuilder;
}
House* Construct(){
pHouseBuilder->BuildPart1();
for (int i = 0; i < 4; i++){
pHouseBuilder->BuildPart2();
}
bool flag=pHouseBuilder->BuildPart3();
if(flag){
pHouseBuilder->BuildPart4();
}
pHouseBuilder->BuildPart5();
return pHouseBuilder->GetResult();
}
};
模式定义: 将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)
- Diector->HouseDirector
- Builder->HouseBuilder
- ConcreteBuilder->StoneHouseBuilder/AdobeHouseBuildr…
要点总结:
- Builder模式主要用于分步骤构建一个复杂对象。在其中分步骤是一稳定的算法,而复杂对象的各个部分则经常变化
- 变化点在哪里 封装哪里——Builder模式主要在于应对复杂对象各个部分的频繁需求变动。其缺点在于难以应对分步骤构建算法的需求变动
- 在Builder模式中,要注意不同语言中构造器内调用虚函数的差别(c++ vs c#)