前言
我们知道,设计模式的终极目标是高内聚,低耦合,好的软件代码必然离不开好的设计。最近在学习设计模式这块的内容,参考的书籍是程杰的《大话设计模式》,这本书对于初学者来说比较友好,易上手,博客里的内容是参考本书以及网络资源整理的。
博客更新基本上是边学边写的过程,写这个专题一是为了作为自己的知识备忘,二是希望能给正在学习设计模式的童鞋一些参考,博客中内容有纰漏或错误之处,还请指出,谢谢。
基本定义
工厂方法模式,属于创建型模式。工厂方法模式定义了一个用于创建工厂对象的公共接口,让子类决定实例化哪一个类。这样使得类实例化(具体产品的创建)延迟到工厂子类中。
UML图
工厂方式模式包含以下几类角色:
AbstractFactory:抽象工厂角色(接口)。提供创建产品的接口(抽象方法)CreateProduct,由具体工厂角色实现。
ConcreteFactory:具体工厂角色。用于实现抽象工厂的抽象方法,完成具体产品的创建。
Product:抽象产品角色,是所有具体产品的父类,定义了产品的规范,主要特性和功能接口等。
ConcreteProduct:具体产品角色,实现抽象产品类中提供的接口,具体产品由具体工厂来创建。
工厂方法模式实例
场景:生活中有很多人都想学雷锋做好事,比如学生、志愿者、工人等。学雷锋做好事的内容主要包括扫地、买米、洗衣等。
这里可以抽象出一个雷锋制造工厂的概念,还可以抽象出一个雷锋类,行使雷锋做好事的内容,下面展开。
UML图
代码实现
1. 雷锋类:提供雷锋做好事行为的接口。
//LeiFeng类
class LeiFeng {
public:
virtual void Sweep(void) = 0;
virtual void BuyRice(void) = 0;
virtual void Wash(void) = 0;
};
2. 学雷锋的大学生类:
class Undergraduate : public LeiFeng {
public:
virtual void Sweep(void)
{
std::cout << "Undergraduate.Sweep!!" << std::endl;
}
virtual void BuyRice(void)
{
std::cout << "Undergraduate.BuyRice!!" << std::endl;
}
virtual void Wash(void)
{
std::cout << "Undergraduate.Wash!!" << std::endl;
}
};
3. 学雷锋的志愿者类:
class Volunteer: public LeiFeng {
public:
virtual void Sweep(void)
{
std::cout << "Volunteer.Sweep!!" << std::endl;
}
virtual void BuyRice(void)
{
std::cout << "Volunteer.BuyRice!!" << std::endl;
}
virtual void Wash(void)
{
std::cout << "Volunteer.Wash!!" << std::endl;
}
};
4. 学雷锋的工人类:
class Worker: public LeiFeng {
public:
virtual void Sweep(void)
{
std::cout << "Worker.Sweep!!" << std::endl;
}
virtual void BuyRice(void)
{
std::cout << "Worker.BuyRice!!" << std::endl;
}
virtual void Wash(void)
{
std::cout << "Worker.Wash!!" << std::endl;
}
};
5. 雷锋工厂
class LeiFengFactory {
public:
virtual LeiFeng* CreateLeiFeng(void) = 0;
};
6. 学雷锋的大学生工厂
class UndergraduateFactory : public LeiFengFactory {
public:
LeiFeng* CreateLeiFeng(void)
{
return new Undergraduate();
}
};
7. 学雷锋的志愿者工厂
class VolunteerFactory : public LeiFengFactory {
public:
LeiFeng* CreateLeiFeng(void)
{
return new Volunteer();
}
};
8. 学雷锋的工人工厂
class WorkerFactory : public LeiFengFactory {
public:
LeiFeng* CreateLeiFeng(void)
{
return new Worker();
}
};
7. 客户端测试代码
int main(int argc, char* argv[])
{
LeiFengFactory *LeiFengFac = new UndergraduateFactory();
LeiFeng* one = LeiFengFac->CreateLeiFeng();
one->Sweep();
one->Wash();
one->BuyRice();
LeiFeng* two = LeiFengFac->CreateLeiFeng();
two->Sweep();
two->Wash();
two->BuyRice();
return 0;
}
优缺点和使用场景
优点:
1.灵活性增强,添加新产品时,只需添加对应的工厂类,无需修改现有代码,符合开闭原则。
2. 用户无需知道产品的具体创建过程,只需知道产品工厂类名。
缺点:
1. 类数量可能较多。
2. 每增加新产品需要增加具体产品类和具体工厂类,增加系统复杂度。
使用场景:
对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化具体工厂,生产出具体的产品。