设计模式------工厂模式
我们今天来接着学习工厂模式,如果还没有看过上一篇简单工厂模式的小伙伴可以点击这里:
什么叫工厂模式
工厂模式是一种设计模式,主要用于解决对象创建的问题,它提供了一个接口用于创建对象,但是让子类决定实例化哪一个类。工厂模式的核心思想是将对象的创建过程封装起来,使客户端不需要知道具体的产品类,只需关心接口即可。这样可以极大地减少代码间的耦合度,增强系统的灵活性和可扩展性。
根据抽象程度和创建对象的复杂度,工厂模式可以细分为以下几种:
- 简单工厂模式(Simple Factory) :
定义一个工厂类,根据传入的参数条件决定创建哪种产品类的实例。工厂类承担了实例化对象的责任,客户端只需调用工厂类的静态方法或实例方法获取所需产品。- 工厂方法模式(Factory Method) :
定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。- 抽象工厂模式(Abstract Factory) :
提供一个接口,用于创建相关或依赖对象家族的多个对象,而不需要指定具体类。它创建的是对象族,而不是单个对象,常用于系统中有多系列产品需要一起创建,且各系列产品间有一定的关联关系。
通过使用工厂模式,你可以:
- 隐藏创建逻辑:客户端无需了解对象是如何创建的。
- 实现依赖倒置原则:高阶模块不依赖于低阶模块的具体实现,而依赖于抽象。
- 降低耦合度:新增产品时,无需修改原有代码,只需新增相应的工厂和产品类。
- 便于扩展:当需要新增产品类型时,只需要新增一个产品类和对应的工厂实现即可。
其中简单工厂模式已经在上篇提及到了,我们来看看这三种工厂模式的区别:
三种工厂模式的区别
让我们用生活中的例子来通俗地解释这三种工厂模式:
- 简单工厂模式(Simple Factory)
假设你是一家快餐店的经理,店里卖汉堡、热狗和披萨。顾客来了只告诉你要吃什么,你(扮演工厂角色)负责根据顾客的要求准备食物。简单工厂就像是你这位经理,顾客说"我要一份汉堡",你就亲自去厨房做出一个汉堡给顾客。
在代码中,简单工厂就是一个静态方法或类,接收一个参数(比如食物类型),然后根据这个参数创建并返回一个相应的产品对象。
- 工厂方法模式(Factory Method)
继续上面的例子,随着业务扩大,你决定开连锁店。这次,每个分店的经理不再需要亲自做汉堡,而是招聘了专门的厨师来做。你制定了一个规定:"每家分店都必须有一个'制作食物'的方法,但具体做什么食物由分店自己决定。"这就像是工厂方法模式,你定义了一个接口(抽象工厂类),要求每个分店(子类)都实现一个"制作食物"的方法,每个分店可以根据当地特色自由决定做什么样的食物。
在代码中,工厂方法模式定义了一个抽象工厂接口,包含一个创建产品的方法,具体的子类会实现这个方法来创建特定的产品对象。
- 抽象工厂模式(Abstract Factory)
后来,你的餐饮帝国发展得更大了,不仅有汉堡、热狗和披萨,还开始经营早餐和甜品。这时你需要一个机制既能创建主食,也能创建饮料和甜品,形成一套完整的餐点组合。于是你设立了中央厨房,这个厨房负责按照地区和时段提供整套菜单(比如美式早餐套装、英式下午茶套装)。这就是抽象工厂,它能创建一系列相关联或互相依赖的产品族。
在代码中,抽象工厂模式定义了一个接口或抽象类,这个接口可以生成一族相关的产品对象,比如一个餐厅抽象工厂可以创建主食工厂、饮料工厂和甜品工厂,每一种工厂又能创建具体的产品。
总结一下,简单工厂模式是集中处理对象创建,工厂方法模式是将对象创建的权利委托给了子类,而抽象工厂模式则关注于创建一组相关的产品对象,它们各有侧重点,适用于不同的应用场景。
工厂方法模式
下面这个例子可以帮助我们了解工厂方法模式:
我们有一个线上教学的班级,现在要给这个班级配置每节课的教学任务,任务的类型有
练习:exam ;家庭作业:homework ;视频:video ;
图文:text ;PPT:ppt ;考试:testpaper ;
请以工厂设计模式来设计该模块的代码应该怎么写。
要求符合:
- 开闭原则;
- 单一职责原则;
- 依赖倒置原则;
- 接口隔离原则;
- 里氏替换原则;
首先工厂方法会有四个部分:抽象任务+具体任务+抽象工厂+具体工厂
cpp
//抽象任务
class Task
{
};
//具体任务
//exam
class Exam : public Task
{
};
//Homework
class Homework : public Task
{
};
//video
class video : public Task
{
};
//text
class text : public Task
{
};
//ppt
class ppt : public Task
{
};
//ppt
class testpaper : public Task
{
};
//抽象工厂
class abstractFactory
{
};
//具体工厂
class realFactory : public abstractFactory
{
};
之后调用具体工厂,我们就可以对应创建相应的类:
cpp
// 客户端代码,使用抽象工厂
void configureLesson(const std::vector<std::string>& tasksTypes, abstractFactory& factory)
{
std::vector<std::unique_ptr<Task>> lessonTasks;
for (const auto& type : tasksTypes)
{
auto task = factory.createTask(type);
lessonTasks.push_back(std::move(task));
}
for(int i = 0; i < lessonTasks.size(); i++)
{
std::cout<<lessonTasks[i]->getTask_name()<<std::endl;
lessonTasks[i]->execte();
std::cout<<std::endl;
}
// 分配任务给学生,执行任务等操作...
}
完整代码如下:
cpp
// 导入必要的头文件
#pragma once
#include<iostream>
#include<cstring>
#include<memory>
#include<vector>
// 抽象任务接口类,定义了任务的基本属性和行为
class Task
{
public:
// 虚拟析构函数,确保派生类能够正确析构
virtual ~Task() {};
// 纯虚函数,用于获取任务名称,所有派生类必须重写此方法
virtual std::string getTask_name() const = 0;
// 纯虚函数,用于执行任务,所有派生类必须重写此方法
virtual void execte() const = 0;
};
// 具体任务类,分别代表不同的任务类型
// Exam(考试任务)
class Exam : public Task
{
public:
std::string getTask_name() const override
{
return "Exam";
}
void execte() const override
{
std::cout << "doing exam" << std::endl;
}
};
// Homework(家庭作业任务)
class Homework : public Task
{
public:
std::string getTask_name() const override
{
return "Homework";
}
void execte() const override
{
std::cout << "doing Homework" << std::endl;
}
};
// video(视频学习任务)
class video : public Task
{
public:
std::string getTask_name() const override
{
return "video";
}
void execte() const override
{
std::cout << "doing video" << std::endl;
}
};
// text(文本阅读任务)
class text : public Task
{
public:
std::string getTask_name() const override
{
return "text";
}
void execte() const override
{
std::cout << "doing text" << std::endl;
}
};
// ppt(演示文稿任务)
class ppt : public Task
{
public:
std::string getTask_name() const override
{
return "ppt";
}
void execte() const override
{
std::cout << "doing ppt" << std::endl;
}
};
// testpaper(试卷任务)
class testpaper : public Task
{
public:
std::string getTask_name() const override
{
return "testpaper";
}
void execte() const override
{
std::cout << "doing testpaper" << std::endl;
}
};
// 抽象工厂接口,定义了创建任务对象的方法
class abstractFactory
{
public:
virtual ~abstractFactory() {};
// 纯虚函数,根据传入的字符串类型创建对应的任务对象
virtual std::unique_ptr<Task> createTask(const std::string& name) const = 0;
};
// 具体工厂类,实现了抽象工厂接口,根据不同类型创建具体任务对象
class realFactory : public abstractFactory
{
public:
std::unique_ptr<Task> createTask(const std::string& type) const override
{
if (type == "Exam")
{
return std::make_unique<Exam>();
}
else if (type == "Homework")
{
return std::make_unique<Homework>();
}
else if (type == "video")
{
return std::make_unique<video>();
}
else
{
// 如果传入的任务类型不支持,则抛出异常
throw std::invalid_argument("Unsupported task type.");
}
}
};
// 客户端代码,使用抽象工厂配置课程任务
void configureLesson(const std::vector<std::string>& tasksTypes, abstractFactory& factory)
{
// 创建存放任务智能指针的容器
std::vector<std::unique_ptr<Task>> lessonTasks;
// 根据任务类型列表,通过工厂创建任务对象并加入容器
for (const auto& type : tasksTypes)
{
auto task = factory.createTask(type);
lessonTasks.push_back(std::move(task)); // 使用移动语义存储任务
}
// 执行并展示所有任务
for (int i = 0; i < lessonTasks.size(); i++)
{
std::cout << lessonTasks[i]->getTask_name() << std::endl;
lessonTasks[i]->execte();
std::cout << std::endl;
}
// 此处省略了分配任务给学生的逻辑及其他操作...
}
这段代码定义了一个抽象任务接口 Task
,并创建了多个具体任务类,同时使用了抽象工厂模式来根据字符串类型动态创建任务对象。在客户端代码中,通过抽象工厂创建了一系列任务,并执行了这些任务。这样做的好处是可以方便地扩展任务类型,同时保持客户端代码的简洁和独立于具体任务实现。