设计模式C++抽象工厂
注:参考视频:【设计模式(完整版)】https://www.bilibili.com/video/BV1Zd4y1t7HK?p=3&vd_source=eee55dc084ebc7a8d4f5db673a3c06f9
分类:(对象)创建型
抽象工厂和工厂方法都是创建型,都是为了解决new一个东西,new的行为都不希望过早的绑定.我们希望他延时,延时有两种方法,一种是通过继承,一种是通过多态.
工厂方法就是通过继承,通过继承以后我们可以重写里面的方法(上一篇博客中的Logistics),而抽象工厂则是把业务单独拎出来,把创建和业务分成两个类.
通过对象还是类来解决问题是站在业务层使用者的角度来说.就像在上图client中有一个factory对象,用对象的方式来解决问题.factory的类型就是AbstractFactory接口,它依赖AbstractFactory接口.
问题:家具城里有沙发,椅子,茶几等产品.产品有不同风格,如现代,北欧风,工业.希望客户收到的出产品风格统一,并可以方便的添加新产品和新风格.(这里不同风格相当于苹果手机搭配安卓充电线,我们想要苹果手机搭配苹果充电线这种统一风格的来使用)
如上图,AbstractFactory就像是一个代工厂,生产两种品牌不同的手机,ConcreteFactory1生产安卓手机,ConcreteProductA1就是生产安卓手机,ConcreteProductB1就是生产安卓手机充电线.ConcreteFactory2生产苹果手机,ConcreteProductA2就是生产苹果手机,ConcreteProductB2就是生产苹果手机充电线.他们生产的ProductA和ProductB都是手机和充电线,通过ConcreteFactory1生产的都是安卓手机配套设备,通过ConcreteFactory2生产的都是苹果手机配套设备,不会乱.
在这个层次上说:工厂方法是一个抽象工厂的一个特例.
例如:我们把AbstractFactory和Client合在一起,换个名字叫Creator,把someOperation()设置为纯虚函数,写两个派生类继承Creator,然后重写someOperation()方法,把new延迟到派生类中创建,左边产品简化一下,灭有ConcreteA1,ConcreteB1,只有ProductA(卡车运输),ProductB(轮船运输),那这样就是工厂方法了.
返回问题:不使用设计模式的原始代码:
#include <iostream>
class Chair
{
public:
virtual ~Chair() {}
virtual void SitOn() const = 0;
};
class ModernChair :public Chair
{
public:
virtual ~ModernChair() {}
virtual void SitOn() const override
{
std::cout << "可以被坐下的ModernChair" << std::endl;
}
};
class ChineseChair :public Chair
{
public:
virtual ~ChineseChair() {}
virtual void SitOn() const override
{
std::cout << "可以被坐下的ChineseChair" << std::endl;
}
};
class Table
{
public:
virtual ~Table() {}
virtual void LayOn() const = 0;
};
class ModernTable :public Table
{
public:
virtual ~ModernTable() {}
virtual void LayOn() const override
{
std::cout << "可以放东西的ModernTable" << std::endl;
}
};
class ChineseTable :public Table
{
public:
virtual ~ChineseTable() {}
virtual void LayOn() const override
{
std::cout << "可以放东西的ChineseTable" << std::endl;
}
};
class Client
{
public:
void buyFurniture()
{
Chair* chair = new ChineseChair();
Table* table = new ModernTable();
chair->SitOn();
table->LayOn();
delete chair;
delete table;
}
};
int main()
{
Client client;
client.buyFurniture();
}
由上代码可知,我们new chair和new table时没有办法保证风格的统一,而且客户每次买东西都要重新修改Client类.
解决方案:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们确定的类.
我们首先保证风格统一,让他new出来的椅子凳子都是ModernStyle,此时使用多态,我们根据抽象工厂的类图,按照延后new的想法来创建类.
#include <iostream>
class Chair
{
public:
virtual ~Chair() {}
virtual void SitOn() const = 0;
};
class ModernChair :public Chair
{
public:
virtual ~ModernChair() {}
virtual void SitOn() const override
{
std::cout << "可以被坐下的ModernChair" << std::endl;
}
};
class ChineseChair :public Chair
{
public:
virtual ~ChineseChair() {}
virtual void SitOn() const override
{
std::cout << "可以被坐下的ChineseChair" << std::endl;
}
};
class Table
{
public:
virtual ~Table() {}
virtual void LayOn() const = 0;
};
class ModernTable :public Table
{
public:
virtual ~ModernTable() {}
virtual void LayOn() const override
{
std::cout << "可以放东西的ModernTable" << std::endl;
}
};
class ChineseTable :public Table
{
public:
virtual ~ChineseTable() {}
virtual void LayOn() const override
{
std::cout << "可以放东西的ChineseTable" << std::endl;
}
};
//新加类
class FurnitureFactory // 抽象工厂
{
public:
virtual Chair* createChair() const = 0;
virtual Table* createTable() const = 0;
};
//新加类 一个具体的生产ModernStyle的工厂
class ModernStyleFactory :public FurnitureFactory
{
public:
virtual Chair* createChair() const override
{
return new ModernChair();
}
virtual Table* createTable() const override
{
return new ModernTable();
}
};
class Client
{
//新加代码 添加一个构造函数,里面传递modern或chinese风格的家具
private:
FurnitureFactory* m_factory;
public:
Client(FurnitureFactory* factory)
{
setFactroy(factory);
}
void buyFurniture()
{
//Chair* chair = new ChineseChair();
//Table* table = new ModernTable();
Chair* chair = m_factory->createChair();
Table* table = m_factory->createTable();
chair->SitOn();
table->LayOn();
delete chair;
delete table;
}
void setFactory(FurnitureFactory* factory)
{
m_factory = factory;
}
};
int main()
{
ModernStyleFactory modernFactory;
Client client(&modernFactory);
client.buyFurniture();
}
而我们添加一个chinese风格的家具也是很简单(放到文章底部了),再来回顾一下抽象工厂类图
client中有一个对象factory,factory依赖于AbstractFactory这个接口,真正的业务在client里面,我们可以通过构造函数来设置factory,也可以通过函数成员setFactory来设置factory,当我们要创建一个具体的产品时,我们要考虑兼容性(苹果手机只能搭配苹果充电线),所以是一族一族的生产(苹果手机和苹果充电线是一个族),所以在例子中命名我们以风格命名而不是以具体的家具(椅子凳子这类)命名.创建根据族来一系列创建.
另一个例子:跨平台UI
跨平台的UI要用到Button和CheckBox,Window平台就用Window的UI,Mac平台的就用Mac的UI,总之要创建就创建一族的UI.而用户去使用的时候就直接利用多态来延迟这种new.这样使用的时候就不会出现我WinButton却搭配了一个MacCheckbox这种问题.
优点:
将一个系列的产品族统一到一起创建.确保系列产品的兼容性
避免客户端和具体产品代码的耦合
单一职责原则.将产品生成代码抽取到同一位置,使得代码易于维护.
开闭原则.向应用程序中引入新产品族时,无需修改客户端代码.
缺点:
在产品族中拓展新的产品需要修改抽象工厂的接口代码.
完整代码:
#include <iostream>
class Chair
{
public:
virtual ~Chair() {}
virtual void SitOn() const = 0;
};
class ModernChair :public Chair //ConcreteProductA1
{
public:
virtual ~ModernChair() {}
virtual void SitOn() const override
{
std::cout << "可以被坐下的ModernChair" << std::endl;
}
};
class ChineseChair :public Chair //ConcreteProductA2
{
public:
virtual ~ChineseChair() {}
virtual void SitOn() const override
{
std::cout << "可以被坐下的ChineseChair" << std::endl;
}
};
class Table
{
public:
virtual ~Table() {}
virtual void LayOn() const = 0;
};
class ModernTable :public Table //ConcreteProductB1
{
public:
virtual ~ModernTable() {}
virtual void LayOn() const override
{
std::cout << "可以放东西的ModernTable" << std::endl;
}
};
class ChineseTable :public Table //ConcreteProductB2
{
public:
virtual ~ChineseTable() {}
virtual void LayOn() const override
{
std::cout << "可以放东西的ChineseTable" << std::endl;
}
};
//新加类
class FurnitureFactory // 抽象工厂 AbstractFactory
{
public:
virtual Chair* createChair() const = 0;
virtual Table* createTable() const = 0;
};
//新加类
class ModernStyleFactory :public FurnitureFactory //ConcreteFactory1
{
public:
virtual Chair* createChair() const override
{
return new ModernChair();
}
virtual Table* createTable() const override
{
return new ModernTable();
}
};
//新加类
class ChineseStyleFactory :public FurnitureFactory //ConcreteFactory2
{
public:
virtual Chair* createChair() const override
{
return new ChineseChair();
}
virtual Table* createTable() const override
{
return new ChineseTable();
}
};
class Client //Client
{
//新加代码
private:
FurnitureFactory* m_factory;
public:
Client(FurnitureFactory* factory)
{
setFactory(factory);
}
void buyFurniture()
{
//Chair* chair = new ChineseChair();
//Table* table = new ModernTable();
Chair* chair = m_factory->createChair();
Table* table = m_factory->createTable();
chair->SitOn();
table->LayOn();
delete chair;
delete table;
}
void setFactory(FurnitureFactory* factory)
{
m_factory = factory;
}
};
int main()
{
ModernStyleFactory modernFactory;
Client client(&modernFactory);
client.buyFurniture();
ChineseStyleFactory chineseFactory;
client.setFactory(&chineseFactory);
client.buyFurniture();
}