简单工厂模式
简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,用于封装对象的创建逻辑。在简单工厂模式中,创建对象的逻辑被封装在一个工厂类中,而不是在客户端直接创建对象。
简单工厂模式的结构组成
-
抽象产品类(Product):即要创建的对象,通常是一个接口或者抽象类,定义了对象的共同接口。
-
具体产品类(Concrete Product):实现了产品接口的具体对象,由工厂类创建。
-
工厂类(Factory):负责创建具体产品的工厂类,包含了对象的创建逻辑。根据客户端传入的参数或者条件,决定创建哪种具体产品的对象,并返回给客户端。
简单工厂模式的工作流程如下
-
客户端通过调用工厂类的方法来创建对象,传入相应的参数或者条件。
-
工厂类根据传入的参数或者条件,决定创建哪种具体产品的对象。
-
工厂类创建具体产品的对象,并返回给客户端。
-
客户端通过返回的对象来使用创建好的产品。
简单工厂模式的优点
-
将对象的创建逻辑封装在工厂类中,提供了一种集中管理和控制对象创建的方式,降低了代码的复杂度和维护成本。
-
客户端通过工厂类来创建对象,不需要直接依赖具体的对象类,从而降低了客户端与具体对象类之间的耦合度,提高了代码的灵活性。
-
工厂类可以根据传入的参数或者条件来决定创建哪种具体产品的对象,从而实现了对象的定制化创建。
简单工厂模式的缺点
-
工厂类可能会变得比较复杂,包含了大量的创建逻辑,不符合开闭原则,难以扩展和维护。
-
当需要创建的产品类型较多时,工厂类的代码可能会变得很复杂和臃肿。
-
对象的创建逻辑集中在工厂类中,可能会导致工厂类的职责过重,不符合单一职责原则。
UML图
代码示例
假设富土康要为三家手机厂商生产手机,富土康总部的人不需要知道工厂是怎么生产的,只要告诉工厂生产哪种类型的手机就行
#include <iostream>
using namespace std;
enum class PHONE {
IPHONE,
XIAOMI,
HUAWEI
};
// 手机抽象类
class phone {
public:
virtual ~phone() {}
virtual void show() = 0;
};
class iPhone : public phone {
public:
void show() { cout << "I'm iPhone" << endl; }
};
class xiaomi : public phone {
public:
void show() { cout << "I'm xiaomi" << endl; }
};
class huawei : public phone {
public:
void show() { cout << "I'm huawei" << endl; }
};
class factory {
public:
phone* makePhone(PHONE PHONE) {
phone* res = nullptr;
switch (PHONE) {
case PHONE::IPHONE:
res = new iPhone();
break;
case PHONE::XIAOMI:
res = new xiaomi();
break;
default:
res = new huawei();
}
return res;
}
};
/*************测试********************/
#include "test.h"
int main()
{
factory f;
phone* p = f.makePhone(PHONE::IPHONE);
p->show();
delete p;
return 0;
}
//输出
I'm iPhone
简单工厂模式的应用场景
简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,用于创建对象的方式。它将对象的创建逻辑封装在一个工厂类中,通过传入不同的参数来创建不同的对象。简单工厂模式适用于以下场景:
-
对象的创建逻辑相对简单且不复杂:简单工厂模式适用于对象的创建逻辑比较简单,不涉及复杂的条件判断或者复杂的算法,只需要根据传入的参数进行简单的处理即可。
-
需要根据不同参数创建不同对象:简单工厂模式适用于根据不同的参数值创建不同类型的对象,例如在一个图形绘制软件中,可以根据传入的参数值创建不同形状的图形对象,如圆形、矩形、三角形等。
-
需要集中管理对象的创建逻辑:简单工厂模式适用于需要集中管理对象的创建逻辑,避免在多个地方散落着对象的创建代码,从而降低了代码的维护成本。
-
需要降低客户端与具体对象类之间的耦合度:简单工厂模式通过将对象的创建逻辑封装在工厂类中,使得客户端代码不直接依赖具体的对象类,从而降低了客户端与具体对象类之间的耦合度,使得客户端更加灵活。
-
需要对对象的创建进行扩展和修改:简单工厂模式适用于将来可能需要对对象的创建逻辑进行扩展或者修改的情况,例如需要增加新的对象类型时,只需要修改工厂类的代码而不需要修改客户端代码。
简单工厂模式并不是一种标准的设计模式,它仅仅是一种简单的对象创建方式,其缺点是工厂类可能会变得比较复杂,不符合开闭原则。在一些复杂的场景中,可能需要考虑使用其他更为灵活和可扩展的创建型设计模式,如工厂方法模式或抽象工厂模式。
工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,用于定义一个创建对象的接口,但将实际的创建过程交给子类来实现。这样可以使得对象的创建与使用相分离,从而实现了更加灵活和可扩展的对象创建方式。
参与角色
- 抽象工厂类:抽象类,提供创建具体产品的接口,由具体工厂类实现。
- 具体工厂类:继承于抽象工厂,实现创建对应具体产品对象的方式。
- 抽象产品类:抽象类,定义了对象的共同接口, 它是具体产品继承的父类。
- 具体产品类:实现了产品接口的具体对象,由具体的工厂类创建
工厂方法模式的工作流程如下
-
客户端通过调用具体工厂类的工厂方法来创建对象。
-
具体工厂类根据工厂方法的实现逻辑,创建具体产品的对象,并返回给客户端。
-
客户端通过返回的对象来使用创建好的产品。
工厂方法模式的优点
-
将对象的创建过程交给子类来实现,实现了对象创建与使用的解耦,提高了代码的灵活性和可扩展性。
-
具体工厂类可以根据需要创建不同类型的产品,满足客户端的不同需求。
-
每个具体工厂类负责创建一种具体产品,符合单一职责原则。
工厂方法模式的缺点
-
每新增一个产品,都需要新增一个具体产品类和一个对应的具体工厂类,导致类的数量增加。
-
客户端需要知道具体工厂类的存在,并选择使用哪个具体工厂类来创建对象,增加了客户端的复杂度。
工厂方法模式适用场景
-
当需要创建的对象具有多种类型,且需要在运行时动态选择其中一种类型时,可以使用工厂方法模式。例如,一个图形绘制软件需要支持多种形状(如圆形、矩形、三角形等),用户在绘制时可以选择不同的形状进行绘制,这时可以使用工厂方法模式来创建不同类型的图形对象。
-
当对象的创建逻辑比较复杂,涉及到多个步骤或者依赖于外部条件时,可以使用工厂方法模式。例如,一个在线购物系统需要根据用户的地理位置和购买记录来选择合适的仓库进行发货,这时可以使用工厂方法模式来根据不同的地理位置和购买记录创建对应的仓库对象。
-
当希望将对象的创建与使用相分离,降低对象间的耦合性,从而提高系统的灵活性和可扩展性时,可以使用工厂方法模式。例如,一个日志记录系统需要根据当前的日志级别创建不同类型的日志记录器,这时可以使用工厂方法模式来创建不同类型的日志记录器对象。
-
当需要符合开闭原则,即对扩展开放,对修改关闭时,可以使用工厂方法模式。新增一种产品时,只需要新增对应的具体产品类和具体工厂类,而不需要修改原有的客户端代码。
总之,工厂方法模式适用于需要根据不同情况创建不同类型的对象,并且希望将对象的创建与使用相分离,同时对产品的种类和创建过程有一定的扩展需求的情况
代码示例
富土康接受了三家手机厂商的订单,但是三家手机厂商对产品的要求不一样,不同的手机制造流程和工艺并不相同,所以在三个不同的工厂生产。
同时还是不需要知道生产细节,只要把订单交给对应的工厂就行,对应的工厂就会为生产出对应的产品
#include <iostream>
using namespace std;
// 手机抽象类
class phone {
public:
virtual ~phone() {}
virtual void show() = 0;
};
class iPhone : public phone {
public:
void show() { cout << "I'm iPhone" << endl; }
};
class xiaomi : public phone {
public:
void show() { cout << "I'm xiaomi" << endl; }
};
class huawei : public phone {
public:
void show() { cout << "I'm huawei" << endl; }
};
class factory {
public:
~factory() {}
virtual phone* makePhone() = 0;
};
class iphoneFac : public factory {
public:
phone* makePhone() {
// do something special
return new iPhone();
}
};
class xiaomiFac : public factory {
public:
phone* makePhone() {
// do something special
return new xiaomi();
}
};
class huaweiFac : public factory {
public:
phone* makePhone() {
// do something special
return new huawei();
}
};
/**********测试代码*****************/
int main()
{
// 生产 iphone
iphoneFac ifac;
phone* p1 = ifac.makePhone();
p1->show();
// 生产小米
xiaomiFac xfac;
phone* p2 = xfac.makePhone();
p2->show();
return 0;
}
// 输出
I'm iPhone
I'm xiaomi
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种抽象的方式来创建一系列相关或相互依赖的对象,而无需指定其具体类别。抽象工厂模式的核心思想是通过定义一个抽象工厂接口,该接口声明了一组用于创建不同产品族的方法,每个方法可以创建一组相关的产品对象,从而实现了一种产品族的创建。
抽象工厂模式包含以下几个角色
-
抽象工厂(Abstract Factory):定义了一组用于创建不同产品族的抽象方法,通常是一个接口或者抽象类。客户端通过调用抽象工厂的方法来创建产品对象,而无需关心具体的产品类。
-
具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体的产品对象。每个具体工厂通常负责创建一个产品族的对象。
-
抽象产品(Abstract Product):定义了产品的抽象接口,通常是一个接口或者抽象类。具体产品类必须实现这个接口或继承这个抽象类。
-
具体产品(Concrete Product):实现了抽象产品接口,具体产品类是具体工厂创建的对象,用于实现客户端的业务需求。
抽象工厂模式的优点
-
提供了一种抽象的方式来创建一系列相关或相互依赖的对象,可以保证这些对象之间的一致性和完整性。
-
可以动态切换不同的具体工厂,从而实现了一种灵活的产品族配置,便于系统的扩展和维护。
-
符合开闭原则,对扩展开放,对修改关闭。新增一种产品族时,只需要新增对应的具体产品类和具体工厂类,而不需要修改原有的客户端代码。
抽象工厂模式的缺点
-
不容易扩展新的产品族:抽象工厂模式在设计时需要提前定义好产品族和产品等级结构,如果需要新增一个产品族,就需要修改抽象工厂接口以及所有的具体工厂类,可能会影响到现有的客户端代码。这样在新增产品族时可能不太灵活,对系统的扩展性有一定限制。
-
增加了系统复杂度:抽象工厂模式引入了抽象工厂接口、具体工厂类、抽象产品接口、具体产品类等多个类和接口,增加了系统的复杂度。对于简单的系统或者产品族不太复杂的情况下,使用抽象工厂模式可能会显得过于繁琐。
-
不支持单一产品的变化:抽象工厂模式主要关注产品族的创建,如果只有一个产品等级结构需要变化,比如新增一个产品类,那么抽象工厂模式可能会显得过于复杂。在这种情况下,可以考虑使用其他的设计模式,如工厂方法模式或者简单工厂模式。
-
违反了开闭原则:虽然抽象工厂模式对于新增产品族比较灵活,但是对于新增产品等级结构时,需要修改抽象工厂接口以及所有的具体工厂类,违反了开闭原则,对修改是开放的。这可能会对系统的维护和扩展带来一定的困扰。
需要根据具体的系统需求和设计目标来综合考虑是否使用抽象工厂模式,避免其潜在的缺点对系统的影响。在某些情况下,可能会有其他更合适的设计模式可以替代抽象工厂模式来满足系统的需求。
抽象工厂模式适用场景
-
当需要创建一系列相关或相互依赖的产品对象,且希望客户端与具体产品的实现解耦时,可以使用抽象工厂模式。
-
当系统需要支持多种不同的产品族,并且希望能够动态切换不同的产品族时,可以使用抽象工厂模式。
-
当希望保持一组相关产品对象的一致性和完整性,避免不合适的产品组合时,可以使用抽象工厂模式。
抽象工厂模式适用于需要创建一系列相关或相互依赖的对象,并且希望通过一种抽象的方式来创建这些对象,实现产品族
代码示例
富土康做了三家厂商的订单后,三家厂商觉得生产的很好,把生产电脑的订单也给了富土康。
于是富土康扩充了工厂,使的对应的工厂也可以生产电脑。
但还是统一管理,只要知道厂商,就可以让对应的工厂生产出厂商想要的产品。
#include <iostream>
using namespace std;
// 手机抽象类
class phone {
public:
virtual ~phone() {}
virtual void show() = 0;
};
class iPhone : public phone {
public:
void show() { cout << "I'm iPhone" << endl; }
};
class xiaomi : public phone {
public:
void show() { cout << "I'm xiaomi" << endl; }
};
class huawei : public phone {
public:
void show() { cout << "I'm huawei" << endl; }
};
// 电脑抽象类
class computer {
public:
virtual ~computer() {}
virtual void show() = 0;
};
class mac : public computer {
public:
void show() { cout << "I'm mac" << endl; }
};
class xiaomiCom : public computer {
public:
void show() { cout << "I'm xiaomi computer" << endl; }
};
class huaweiCom : public computer {
public:
void show() { cout << "I'm huawei computer" << endl; }
};
class factory {
public:
~factory() {}
virtual phone* makePhone() = 0;
virtual computer* makeComputer() = 0;
};
class iphoneFac : public factory {
public:
phone* makePhone() {
// do something
return new iPhone();
}
computer* makeComputer() {
// do somethine
return new mac();
}
};
class xiaomiFac : public factory {
public:
phone* makePhone() {
// do something
return new xiaomi();
}
computer* makeComputer() {
// do something
return new xiaomiCom();
}
};
class huaweiFac : public factory {
public:
phone* makePhone() {
// do something
return new huawei();
}
computer* makeComputer() {
// do something
return new huaweiCom();
}
};
/*************测试代码*****************/
#include "test.h"
int main()
{
// 生产 iphone
iphoneFac ifac;
phone* p1 = ifac.makePhone();
computer* c1 = ifac.makeComputer();
p1->show();
c1->show();
// 生产小米
xiaomiFac xfac;
phone* p2 = xfac.makePhone();
computer* c2 = xfac.makeComputer();
p2->show();
c2->show();
return 0;
}
// 输出
I'm iPhone
I'm mac
I'm xiaomi
I'm xiaomi computer
总结
需要根据具体的系统需求和设计目标来综合考虑是否使用某种模式,避免其潜在的缺点对系统的影响。
提示:
可以使用模板类减少增加新的工厂或产品时需要添加的代码量