简单工厂模式、工厂模式、抽象工厂模式,为常见且常用的三种设计模式,下面我将这三种设计模式放在一起,讲解每种设置模式的概念、特点、使用场景(使用Qt实现),以及三种设计模式的区别。
目录
一、简单工厂模式
1.概念
简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它提供了一个单一的工厂类,用于创建不同类型的对象,根据客户端的需求来决定创建哪种具体类型的对象。简单工厂模式将对象的创建过程封装在一个工厂类中,客户端只需要向工厂类请求需要的对象,而无需了解对象的具体创建细节。
以下是简单工厂模式的核心组成部分和使用方法:
产品类(Product):产品是需要被创建的对象,通常包含多个属性和方法。
工厂类(Factory):工厂类包含一个或多个创建产品对象的方法,根据客户端的请求来选择并创建具体的产品对象。
使用简单工厂模式的步骤如下:
(1)创建产品类,定义产品的属性和方法。
(2)创建工厂类,包含一个或多个方法,用于创建不同类型的产品对象。
(3)在客户端中,通过工厂类来创建产品对象,传递一个参数或条件给工厂类,以指示需要创建哪种具体类型的产品对象。
(4)工厂类根据客户端的请求,调用相应的创建方法来实例化产品对象,并将其返回给客户端。
简单工厂模式的使用场景包括:
-
对象的创建过程相对简单:当对象的创建过程不太复杂,只涉及一些简单的初始化操作时,简单工厂模式是一个适合的选择。
-
对象的种类不太多:当需要创建的对象种类不是特别多,且不经常发生变化时,可以考虑使用简单工厂模式。
-
客户端不需要关心对象的创建细节:简单工厂模式将对象的创建过程封装在工厂类中,客户端只需调用工厂类的方法来创建对象,无需关心对象的具体创建过程。
-
对象的创建过程需要统一管理:如果需要对对象的创建过程进行集中管理和维护,简单工厂模式可以提供一个统一的入口点。
简单工厂模式的主要优点是隐藏了对象创建的复杂性,使客户端代码更加简洁和可维护。然而,它的扩展性相对较差,因为每次新增类型的对象都需要修改工厂类。如果系统需要支持多种不同类型的对象,并且这些对象的创建过程较为复杂,可以考虑使用工厂方法模式或抽象工厂模式,这两种模式更具扩展性。
2.代码示例
// Operation.h
#ifndef OPERATION_H
#define OPERATION_H
#include <QString>
class Operation
{
public:
Operation();
double getNumberA();
double getNumberB();
void setNumberA(double number);
void setNumberB(double number);
virtual double getResult() = 0;
private:
double m_numberA;
double m_numberB;
};
class OperationAdd : public Operation
{
public:
double getResult();
};
class OperationSub : public Operation
{
public:
double getResult();
};
class OperationMul : public Operation
{
public:
double getResult();
};
class OperationDiv : public Operation
{
public:
double getResult();
};
class OperationFactory
{
public:
static Operation* creatorOperate(QString operate);
};
#endif // OPERATION_H
// Operation.cpp
#include "operation.h"
Operation::Operation()
{
}
double Operation::getNumberA()
{
return m_numberA;
}
double Operation::getNumberB()
{
return m_numberB;
}
void Operation::setNumberA(double number)
{
m_numberA = number;
}
void Operation::setNumberB(double number)
{
m_numberB = number;
}
double OperationAdd::getResult()
{
double result = 0;
result = getNumberA() + getNumberB();
return result;
}
double OperationSub::getResult()
{
double result = 0;
result = getNumberA() - getNumberB();
return result;
}
double OperationMul::getResult()
{
double result = 0;
result = getNumberA() * getNumberB();
return result;
}
double OperationDiv::getResult()
{
double result = 0;
if(getNumberB() == 0)
return 0;
result = getNumberA() / getNumberB();
return result;
}
Operation* OperationFactory::creatorOperate(QString operate)
{
Operation* oper = nullptr;
if(operate == "+")
{
OperationAdd* operAdd = new OperationAdd();
oper = operAdd;
}
else if(operate == "-")
{
OperationSub* operSub = new OperationSub();
oper = operSub;
}
else if(operate == "*")
{
OperationMul* operMul = new OperationMul();
oper = operMul;
}
else if(operate == "/")
{
OperationDiv* operDiv = new OperationDiv();
oper = operDiv;
}
else
{
oper = new OperationAdd();
}
return oper;
}
// main.cpp
#include <QCoreApplication>
#include <iostream>
#include "operation.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Operation* oper = nullptr;
double numberA;
double numberB;
char operation;
cout << "Please input numberA: ";
cin >> numberA;
cout << "Please input operator symbol: ";
cin >> operation;
cout << "Please input numberB: " ;
cin >> numberB;
oper = OperationFactory::creatorOperate(QString(operation));
oper->setNumberA(numberA);
oper->setNumberB(numberB);
double result = oper->getResult();
cout << result;
return a.exec();
}
该示例为计算器,输入数值A,输入计算符号+、 -、 *、 /,输入数值B,在OperationFactory工厂中,创建执行相应算法的对象,然后进行数据赋值,计算得到结果并输出。
3.代码分析
工厂类中包含了必要的逻辑判断,根据客户端的选择条件,动态实例化相关的类,客户端摆脱了与具体产品的依赖。
增加新产品时,除了需要编写新产品相关业务代码,还需扩展原有工厂创建产品处的逻辑代码。
二、工厂模式
1.概念
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种将对象的创建过程延迟到子类的方式。工厂方法模式将对象的实例化委托给子类,每个具体子类都负责创建特定类型的对象。这使得客户端代码与具体对象的创建过程解耦,同时支持了灵活的对象创建和扩展。
以下是工厂方法模式的核心组成部分和使用方法:
产品类(Product):产品是需要被创建的对象,通常包含多个属性和方法。
抽象工厂类(Factory):抽象工厂类定义了一个抽象的工厂方法,该方法返回一个抽象产品类型。工厂类可以包含多个工厂方法,每个方法负责创建不同类型的产品。
具体工厂类(Concrete Factory):具体工厂类实现了抽象工厂类中定义的工厂方法,负责具体的产品创建。每个具体工厂类通常对应一种具体产品类型。
使用工厂方法模式的步骤如下:
(1)创建产品类,定义产品的属性和方法。
(2)创建抽象工厂类,定义一个或多个抽象的工厂方法,用于创建不同类型的产品。
(3)创建具体工厂类,实现抽象工厂类中定义的工厂方法,负责创建具体的产品对象。
(4)在客户端中,使用具体工厂类来创建产品对象,无需关心具体产品的创建过程。客户端只需调用工厂方法来获取产品对象。
工厂方法模式的使用场景包括:
-
需要创建一组相关但不同类型的对象:工厂方法模式适用于创建一组相关的对象,每个对象具有共同的接口但有不同的实现。
-
客户端需要与具体对象的创建过程解耦:工厂方法模式将对象的创建委托给具体工厂类,客户端只需与抽象工厂类和产品类交互,无需了解具体对象的创建过程。
-
支持扩展:工厂方法模式支持添加新的产品类型和具体工厂类,而无需修改现有的代码,从而实现系统的可扩展性。
-
实现多态性:工厂方法模式促使客户端使用多态性来处理不同类型的产品对象,从而增强了代码的灵活性和可维护性。
-
复杂对象的构建:当对象的构建过程比较复杂,包括多个步骤或需要特定的配置时,工厂方法模式可以更好地管理这些复杂性。
工厂方法模式的主要优点是支持灵活的对象创建和扩展,使系统更具可维护性和可扩展性。它适用于需要创建一组相关对象,同时需要降低客户端与具体对象创建细节之间的耦合度的情况。不过,工厂方法模式可能会引入较多的类和接口,因此在设计时需要权衡和考虑是否真正需要这种分离。
2.代码示例
// operationfactory.h
#ifndef OPERATIONFACTORY_H
#define OPERATIONFACTORY_H
class Operation
{
public:
Operation();
double getNumberA();
double getNumberB();
void setNumberA(double number);
void setNumberB(double number);
virtual double getResult() = 0;
private:
double m_numberA;
double m_numberB;
};
class OperationAdd : public Operation
{
public:
double getResult();
};
class OperationSub : public Operation
{
public:
double getResult();
};
class OperationMul : public Operation
{
public:
double getResult();
};
class OperationDiv : public Operation
{
public:
double getResult();
};
class OperationFactory
{
public:
virtual Operation* createOperation() = 0;
};
class OperationAddFactory : public OperationFactory
{
public:
Operation* createOperation();
};
class OperationSubFactory : public OperationFactory
{
public:
Operation* createOperation();
};
class OperationMulFactory : public OperationFactory
{
public:
Operation* createOperation();
};
class OperationDivFactory : public OperationFactory
{
public:
Operation* createOperation();
};
#endif // OPERATIONFACTORY_H
// operationfactory.cpp
#include "operationfactory.h"
Operation::Operation()
{
}
double Operation::getNumberA()
{
return m_numberA;
}
double Operation::getNumberB()
{
return m_numberB;
}
void Operation::setNumberA(double number)
{
m_numberA = number;
}
void Operation::setNumberB(double number)
{
m_numberB = number;
}
double OperationAdd::getResult()
{
double result = 0;
result = getNumberA() + getNumberB();
return result;
}
double OperationSub::getResult()
{
double result = 0;
result = getNumberA() - getNumberB();
return result;
}
double OperationMul::getResult()
{
double result = 0;
result = getNumberA() * getNumberB();
return result;
}
double OperationDiv::getResult()
{
double result = 0;
if(getNumberB() == 0)
return 0;
result = getNumberA() / getNumberB();
return result;
}
Operation* OperationAddFactory::createOperation()
{
return new OperationAdd();
}
Operation* OperationSubFactory::createOperation()
{
return new OperationSub();
}
Operation* OperationMulFactory::createOperation()
{
return new OperationMul();
}
Operation* OperationDivFactory::createOperation()
{
return new OperationDiv();
}
// main.cpp
#include <QCoreApplication>
#include <iostream>
#include "operationfactory.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
double numberA;
double numberB;
char operationC;
QString operationStr;
cout << "Please input numberA: ";
cin >> numberA;
cout << "Please input operator symbol: ";
cin >> operationC;
operationStr = QString(operationC);
cout << "Please input numberB: " ;
cin >> numberB;
OperationFactory *factory = nullptr;
if(operationStr == "+")
{
factory = new OperationAddFactory();
}
else if(operationStr == "-")
{
factory = new OperationSubFactory();
}
else if(operationStr == "*")
{
factory = new OperationMulFactory();
}
else if(operationStr == "/")
{
factory = new OperationDivFactory();
}
else
{
cout << "Input symbol error!";
}
Operation *operation = factory->createOperation();
operation->setNumberA(numberA);
operation->setNumberB(numberB);
double result = operation->getResult();
cout << result;
return a.exec();
}
3.代码分析
把简单工厂的创建产品逻辑判断,移动到客户端代码中,使产品的实例化延迟到其子类。
三、抽象工厂模式
1.概念
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种方式来创建一组相关或依赖对象,而无需指定它们的具体类。抽象工厂模式基于工厂方法模式,不仅创建单一对象,而是创建一组对象,这组对象通常具有某种关联或共同的主题。
以下是抽象工厂模式的核心组成部分和使用方法:
抽象工厂接口(Abstract Factory):抽象工厂接口定义了一组用于创建相关对象的抽象方法,每个方法负责创建一种对象。通常,一个抽象工厂接口对应一个产品族,其中的方法对应不同类型的产品。
具体工厂类(Concrete Factory):具体工厂类实现了抽象工厂接口,负责创建一组相关的对象。每个具体工厂类通常对应一种产品族,它实现了抽象工厂接口中的方法,从而创建具体的产品对象。
抽象产品接口(Abstract Product):抽象产品接口定义了一组产品的通用接口,包括产品的属性和方法。
具体产品类(Concrete Product):具体产品类实现了抽象产品接口,负责实现具体产品的属性和方法。
使用抽象工厂模式的步骤如下:
(1)创建抽象产品接口,定义产品的通用接口,包括属性和方法。
(2)创建抽象工厂接口,定义一组抽象方法,每个方法用于创建不同类型的产品。
(3)创建具体产品类,实现抽象产品接口,定义具体产品的属性和方法。
(4)创建具体工厂类,实现抽象工厂接口中的方法,负责创建一组相关的产品对象。
(5)在客户端中,选择合适的具体工厂类,然后使用工厂方法来创建一组相关的产品对象。
抽象工厂模式的使用场景包括:
-
需要创建一组相关的对象:当系统需要一组相关或依赖的对象,而这些对象通常一起使用或一起构建时,抽象工厂模式是一个适合的选择。
-
客户端需要与具体对象的创建过程解耦:抽象工厂模式将对象的创建委托给具体工厂类,客户端只需与抽象工厂接口和抽象产品接口交互,无需了解具体对象的创建细节。
-
支持产品族扩展:抽象工厂模式支持添加新的产品族(一组相关的产品),而不需要修改现有的代码,从而实现系统的可扩展性。
-
强调一致性:抽象工厂模式强调创建一组产品的一致性,确保这组产品之间的关联和兼容性。
-
复杂对象的构建:当对象的构建过程较为复杂,包括多个步骤或需要特定的配置时,抽象工厂模式可以更好地管理这些复杂性。
抽象工厂模式有助于提高系统的灵活性和可维护性,同时支持一组相关对象的创建和管理。它适用于需要创建一组相关产品的情况,以及需要将对象的创建过程与客户端解耦的情况。不过,抽象工厂模式可能会引入多个接口和类,因此在设计时需要仔细权衡和考虑是否真正需要这种分离。
2.代码示例
// abstractfactory.h
#ifndef ABSTRACTFACTORY_H
#define ABSTRACTFACTORY_H
#include <QString>
//用户表
class User
{
public:
int getId();
void setId(int id);
QString getName();
void serName(QString name);
private:
int m_id;
QString m_name;
};
class IUser
{
public:
virtual void Insert(User* user) = 0;
virtual User* GetUser(int id) = 0;
};
class SqlserverUser : public IUser
{
public:
void Insert(User *user);
User* GetUser(int id);
};
class AccessUser : public IUser
{
public:
void Insert(User *user);
User* GetUser(int id);
};
//部门表
class Department
{
public:
int getId();
void setId(int id);
QString getName();
void setName(QString name);
private:
int m_id;
QString m_deptName;
};
class IDepartment
{
public:
virtual void Insert(Department* department) = 0;
virtual Department* GetDepartment(int id) = 0;
};
class SqlserverDepartment : public IDepartment
{
public:
void Insert(Department* department);
Department* GetDepartment(int id);
};
class AccessDepartment : public IDepartment
{
public:
void Insert(Department* department);
Department* GetDepartment(int id);
};
//工厂
class IFactory
{
public:
virtual IUser* CreateUser() = 0;
virtual IDepartment* CreateDepartment() = 0;
};
class SqlserverFactory : public IFactory
{
public:
IUser* CreateUser();
IDepartment* CreateDepartment();
};
class AccessFactory : public IFactory
{
public:
IUser* CreateUser();
IDepartment* CreateDepartment();
};
#endif // ABSTRACTFACTORY_H
// abstractfactory.cpp
#include "abstractfactory.h"
#include <QDebug>
int User::getId()
{
return m_id;
}
void User::setId(int id)
{
m_id = id;
}
QString User::getName()
{
return m_name;
}
void User::serName(QString name)
{
m_name = name;
}
void SqlserverUser::Insert(User *user)
{
qDebug()<<"在SQL Server中给User表增加一条记录";
}
User* SqlserverUser::GetUser(int id)
{
qDebug()<<"在SQL Server中给根据ID得到User表一条记录";
return NULL;
}
void AccessUser::Insert(User *user)
{
qDebug()<<"在Access中给User表增加一条记录";
}
User* AccessUser::GetUser(int id)
{
qDebug()<<"在Access中给根据ID得到User表一条记录";
return NULL;
}
int Department::getId()
{
return m_id;
}
void Department::setId(int id)
{
m_id = id;
}
QString Department::getName()
{
return m_deptName;
}
void Department::setName(QString name)
{
m_deptName = name;
}
void SqlserverDepartment::Insert(Department *department)
{
qDebug()<<"在SQL Server中给Department表增加一条记录";
}
Department * SqlserverDepartment::GetDepartment(int id)
{
qDebug()<<"在SQL Server中根据ID得到Department表一条记录";
return NULL;
}
void AccessDepartment::Insert(Department *department)
{
qDebug()<<"在Access中给Department表增加一条记录";
}
Department * AccessDepartment::GetDepartment(int id)
{
qDebug()<<"在Access中根据ID得到Department表一条记录";
return NULL;
}
IUser* SqlserverFactory::CreateUser()
{
return new SqlserverUser();
}
IDepartment* SqlserverFactory::CreateDepartment()
{
return new SqlserverDepartment();
}
IUser* AccessFactory::CreateUser()
{
return new AccessUser();
}
IDepartment* AccessFactory::CreateDepartment()
{
return new AccessDepartment();
}
// main.cpp
#include <QCoreApplication>
#include "abstractfactory.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
User *user = new User();
Department *dept = new Department();
// IFactory *factory = new SqlserverFactory();
IFactory *factory = new AccessFactory();
IUser *iu = factory->CreateUser();
iu->Insert(user);
iu->GetUser(1);
IDepartment *id = factory->CreateDepartment();
id->Insert(dept);
id->GetDepartment(1);
return a.exec();
}
3.代码分析
抽象工厂模式,让创建实例的过程与客户端分离,客户端通过抽象接口操纵实例。
四、总结
简单工厂模式、工厂模式和抽象工厂模式是三种与对象创建相关的设计模式,它们有不同的用途和特点。以下是它们之间的主要区别:
-
简单工厂模式(Simple Factory Pattern):
-
定义:简单工厂模式是一种创建型模式,它通过一个工厂类来创建对象,根据传递给工厂的参数或条件来决定创建哪种具体类型的对象。
-
特点:
- 有一个单一的工厂类,负责对象的创建。
- 客户端通过工厂类来创建对象,无需了解对象的具体创建过程。
- 工厂类通常包括一个或多个创建对象的方法。
-
用法:简单工厂模式通常用于隐藏对象的创建细节,使客户端代码与具体对象的创建解耦。但它的扩展性相对较差,因为每次新增类型的对象都需要修改工厂类。
-
-
工厂模式(Factory Method Pattern):
-
定义:工厂模式是一种创建型模式,它定义一个接口,但将对象的实际创建延迟到子类中,从而允许不同的子类决定创建哪种具体类型的对象。
-
特点:
- 包括一个抽象工厂接口,由具体的子类来实现。
- 每个具体的子类负责创建一种具体类型的对象。
- 客户端通过调用工厂方法来创建对象,无需关心对象的具体类型。
-
用法:工厂模式允许在运行时选择不同的工厂子类来创建对象,从而支持扩展,但仍然需要修改工厂类结构以添加新的对象类型。
-
-
抽象工厂模式(Abstract Factory Pattern):
-
定义:抽象工厂模式是一种创建型模式,它提供一个接口,用于创建一组相关或依赖对象,而不指定其具体类。它是工厂方法模式的扩展,用于创建一组相关的对象。
-
特点:
- 包括一个抽象工厂接口,定义一组相关对象的创建方法。
- 每个具体的工厂子类实现了抽象工厂接口,负责创建一组相关的对象。
- 客户端通过工厂接口来创建一组相关的对象,无需关心对象的具体类。
-
用法:抽象工厂模式适用于创建一组相关的对象,例如不同操作系统的界面组件(按钮、文本框等)。它允许客户端使用不同的工厂实现来创建对象,从而实现整体的替换。
-
总之,简单工厂模式主要用于隐藏对象的创建细节,工厂模式允许不同的子类决定创建哪种对象,而抽象工厂模式用于创建一组相关的对象,并且提供了更高层次的抽象,使客户端能够创建整组对象而不必关心具体类的选择。选择使用哪种模式取决于你的具体需求和设计目标。