【再谈设计模式】抽象工厂模式~对象创建的统筹者
一、引言
在软件开发的世界里,高效、灵活且易于维护的代码结构是每个开发者追求的目标。设计模式就像是建筑蓝图中的经典方案,为我们提供了应对各种常见问题的有效策略。其中,抽象工厂模式在对象创建方面扮演着重要的角色,它如同一个统筹者,精心组织着一系列相关对象的创建过程,确保整个系统的高效运转和易于扩展。无论是构建大型企业级应用还是小型工具软件,理解和运用抽象工厂模式都能让我们的代码更加优雅、健壮。
二、定义与描述
抽象工厂设计模式是一种创建对象的设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。简单来说,抽象工厂模式就像是一个工厂的抽象层,这个抽象层定义了创建多种不同类型产品的方法,但不涉及具体产品的创建细节。
三、抽象背景
在软件开发中,当系统需要创建一系列相关的对象时,例如一个游戏可能需要创建不同类型的角色(战士、法师等)以及与这些角色相关的武器、装备等对象。如果直接在代码中实例化这些对象,将会导致代码的高度耦合,即对象的创建逻辑与使用逻辑紧密地交织在一起。当需要添加新的角色类型或者修改对象的创建逻辑时,就需要在大量的代码中进行修改,这不仅容易出错,而且维护成本极高。抽象工厂模式的出现就是为了解决这种对象创建的复杂性和耦合性问题。
四、适用场景与现实问题解决
(一)适用场景
- 多平台应用开发
- 当开发一个跨平台的应用时,例如同时支持Windows、Linux和Mac操作系统的图形界面应用。不同平台下的窗口、按钮、菜单等界面组件虽然功能相似,但实现方式不同。抽象工厂模式可以用于创建与特定平台相关的界面组件系列,使得代码能够轻松地在不同平台间切换,而不需要在每个使用界面组件的地方都进行大量的条件判断。
- 游戏开发
- 在游戏中,不同的游戏场景可能需要不同类型的游戏元素。例如,一个冒险游戏可能有森林场景、沙漠场景等,每个场景中都有独特的怪物、道具和地形。抽象工厂模式可以用来创建这些与特定场景相关的游戏元素系列,保证游戏元素之间的兼容性和一致性。
(二)现实问题解决
- 假设我们正在开发一个汽车制造系统。汽车由多个部件组成,如发动机、轮胎、座椅等,并且有不同类型的汽车,如轿车、SUV等。使用抽象工厂模式,我们可以创建抽象的汽车部件工厂,它定义了创建发动机、轮胎和座椅等部件的抽象方法。然后针对轿车和SUV分别创建具体的工厂实现类,这些具体工厂类负责创建各自类型汽车所需的特定部件。这样,当需要添加一种新类型的汽车时,只需要创建一个新的具体工厂类,而不需要修改使用这些部件的汽车组装代码,从而降低了系统的耦合度,提高了可维护性和可扩展性。
五、现实生活的例子
以家具制造为例。家具厂可以看作是一个抽象工厂,它有生产不同风格家具(如现代风格、古典风格)的能力。对于现代风格家具,工厂可以生产现代风格的沙发、餐桌和椅子;对于古典风格家具,工厂可以生产古典风格的沙发、餐桌和椅子。这里,家具厂就是抽象工厂,它定义了生产沙发、餐桌和椅子的抽象方法,而现代风格家具厂和古典风格家具厂就是具体的工厂实现类,它们按照各自的风格生产具体的家具产品。
六、初衷与问题解决
- 初衷:抽象工厂模式的初衷是为了将对象的创建和使用分离,提高代码的灵活性和可维护性。通过提供一个抽象的创建对象的接口,使得代码的依赖关系更加抽象化,减少对具体类的依赖。
- 问题解决:它解决了对象创建逻辑与使用逻辑耦合的问题。在大型软件系统中,如果没有这种模式,每当需要创建新类型的对象或者修改对象的创建逻辑时,可能需要在多个地方修改代码。而抽象工厂模式通过将对象创建逻辑封装在具体的工厂类中,只需要修改或扩展工厂类,而不需要影响使用这些对象的其他代码部分。
七、代码示例
(一)Java示例
// 抽象产品:座椅
interface Seat {
void sitOn();
}
// 抽象产品:轮胎
interface Tire {
void roll();
}
// 抽象产品:发动机
interface Engine {
void start();
}
// 抽象工厂
interface CarFactory {
Seat createSeat();
Tire createTire();
Engine createEngine();
}
// 具体产品:轿车座椅
class SedanSeat implements Seat {
@Override
public void sitOn() {
System.out.println("坐在轿车座椅上。");
}
}
// 具体产品:轿车轮胎
class SedanTire implements Tire {
@Override
public void roll() {
System.out.println("轿车轮胎滚动。");
}
}
// 具体产品:轿车发动机
class SedanEngine implements Engine {
@Override
public void start() {
System.out.println("轿车发动机启动。");
}
}
// 具体工厂:轿车工厂
class SedanFactory implements CarFactory {
@Override
public Seat createSeat() {
return new SedanSeat();
}
@Override
public Tire createTire() {
return new SedanTire();
}
@Override
public Engine createEngine() {
return new SedanEngine();
}
}
public class Main {
public static void main(String[] args) {
CarFactory sedanFactory = new SedanFactory();
Seat sedanSeat = sedanFactory.createSeat();
Tire sedanTire = sedanFactory.createTire();
Engine sedanEngine = sedanFactory.createEngine();
sedanSeat.sitOn();
sedanTire.roll();
sedanEngine.start();
}
}
(二)C++示例
#include <iostream>
// 抽象产品:座椅
class Seat {
public:
virtual void sitOn() = 0;
};
// 抽象产品:轮胎
class Tire {
public:
virtual void roll() = 0;
};
// 抽象产品:发动机
class Engine {
public:
virtual void start() = 0;
};
// 抽象工厂
class CarFactory {
public:
virtual Seat* createSeat() = 0;
virtual Tire* createTire() = 0;
virtual Engine* createEngine() = 0;
};
// 具体产品:轿车座椅
class SedanSeat : public Seat {
public:
void sitOn() override {
std.out << "坐在轿车座椅上。" << std::endl;
}
};
// 具体产品:轿车轮胎
class SedanTire : public Tire {
public:
void roll() override {
std::cout << "轿车轮胎滚动。" << std::endl;
}
};
// 具体产品:轿车发动机
class SedanEngine : public Engine {
public:
void start() override {
std::cout << "轿车发动机启动。" << std::endl;
}
};
// 具体工厂:轿车工厂
class SedanFactory : public CarFactory {
public:
Seat* createSeat() override {
return new SedanSeat();
}
Tire* createTire() override {
return new SedanTire();
}
Engine* createEngine() override {
return new SedanEngine();
}
};
int main() {
CarFactory* sedanFactory = new SedanFactory();
Seat* sedanSeat = sedanFactory->createSeat();
Tire* sedanTire = sedanFactory->createTire();
Engine* sedanEngine = sedanFactory->createEngine();
sedanSeat->sitOn();
sedanTire->roll();
sedanEngine->start();
delete sedanSeat;
delete sedanTire;
delete sedanEngine;
delete sedanFactory;
return 0;
}
(三)Python示例
# 抽象产品:座椅
class Seat:
def sitOn(self):
pass
# 抽象产品:轮胎
class Tire:
def roll(self):
pass
# 抽象产品:发动机
class Engine:
def start(self):
pass
# 抽象工厂
class CarFactory:
def createSeat(self):
pass
def createTire(self):
pass
def createEngine(self):
pass
# 具体产品:轿车座椅
class SedanSeat(Seat):
def sitOn(self):
print("坐在轿车座椅上。")
# 具体产品:轿车轮胎
class SedanTire(Tire):
def roll(self):
print("轿车轮胎滚动。")
# 具体产品:轿车发动机
class SedanEngine(Engine):
def start(self):
print("轿车发动机启动。")
# 具体工厂:轿车工厂
class SedanFactory(CarFactory):
def createSeat(self):
return SedanSeat()
def createTire(self):
return SedanTire()
def createEngine(self):
return SedanEngine()
if __name__ == "__main__":
sedanFactory = SedanFactory()
sedanSeat = sedanFactory.createSeat()
sedanTire = sedanFactory.createTire()
sedanEngine = sedanFactory.createEngine()
sedanSeat.sitOn();
sedanTire.roll();
sedanEngine.start();
(四)Go示例
// 抽象产品:座椅
type Seat interface {
SitOn()
}
// 抽象产品:轮胎
type Tire interface {
Roll()
}
// 抽象产品:发动机
type Engine interface {
Start()
}
// 抽象工厂
type CarFactory interface {
CreateSeat() Seat
CreateTire() Tire
CreateEngine() Engine
}
// 具体产品:轿车座椅
type SedanSeat struct{}
func (s SedanSeat) SitOn() {
println("坐在轿车座椅上。")
}
// 具体产品:轿车轮胎
type SedanTire struct{}
func (s SedanTire) Roll() {
println("轿车轮胎滚动。")
}
// 具体产品:轿车发动机
type SedanEngine struct{}
func (s SedanEngine) Start() {
println("轿车发动机启动。")
}
// 具体工厂:轿车工厂
type SedanFactory struct{}
func (s SedanFactory) CreateSeat() Seat {
return SedanSeat{}
}
func (s SedanFactory) CreateTire() Tire {
return SedanTire{}
}
func (s SedanFactory) CreateEngine() Engine {
return SedanEngine{}
}
func main() {
sedanFactory := SedanFactory{}
sedanSeat := sedanFactory.CreateSeat()
sedanTire := sedanFactory.CreateTire()
sedanEngine := sedanFactory.CreateEngine()
sedanSeat.SitOn()
sedanTire.Roll()
sedanEngine.Start()
}
八、抽象工厂设计模式的优缺点
(一)优点
- 解耦对象的创建和使用
- 使用者不需要知道对象的具体创建过程,只需要关心如何使用对象。这使得代码的职责更加清晰,有利于团队开发和代码维护。
- 提高代码的可维护性和可扩展性
- 当需要添加新的产品类型或者修改产品的创建逻辑时,只需要在具体的工厂类中进行操作,不需要修改使用这些对象的其他代码部分。
- 便于代码的复用
- 抽象工厂可以被多个地方复用,只要这些地方需要创建相同系列的产品。同时,具体的产品类也可以在其他场景下复用。
(二)缺点
- 增加代码复杂度
- 引入抽象工厂模式需要创建更多的类和接口,对于简单的应用场景,可能会使代码变得过于复杂。
- 不易于理解
- 对于初学者或者不熟悉设计模式的开发人员来说,抽象工厂模式的概念和实现方式可能比较难以理解,需要一定的学习成本。
九、抽象工厂设计模式的升级版
- 抽象工厂模式的一个升级版是工厂方法模式的组合使用。在大型系统中,可能会存在多个抽象工厂,每个抽象工厂又可以有多个具体的工厂方法。这种组合模式可以进一步细化对象的创建逻辑,提高代码的灵活性。例如,在汽车制造系统中,可以先有一个抽象的汽车部件总装工厂(抽象工厂),然后这个总装工厂中的每个部件创建可以采用工厂方法模式,即发动机的创建有专门的发动机工厂方法,轮胎的创建有专门的轮胎工厂方法等。这样可以更加细致地管理和扩展对象的创建逻辑。