在面向对象编程中,通常通过继承和虚函数来提供抽象能力,多态性使得程序在运行时,调用者只需处理父类类型,而无需关注具体的子类类型。例如,在一个游戏中,活动对象为动物,如老虎和猫,它们会对主角进行攻击。实现可能如下所示:

代码如下:
class Animal {
public:
virtual void Attack() = 0;
};
<p>class Tiger : public Animal {
public:
virtual void Attack() {
std::cout << "Tiger Attack!" << std::endl;
}
};</p><p>class Cat : public Animal {
public:
virtual void Attack() {
std::cout << "Cat Attack!" << std::endl;
}
};如果外部有一个方法,不需要关心具体的对象类型,只需使用基类Animal的指针来操作对象,通过多态机制可以实现对具体对象类型的方法调用:
void Attack(Animal<em> pAnimal) {
pAnimal->Attack();
}调用方式如下(忽略内存释放问题):
Animal</em> pAnimal = new Tiger; Attack(pAnimal); pAnimal = new Cat; Attack(pAnimal);
输出结果为:
Tiger Attack! Cat Attack!
上述多态示例表明,在程序实现时,只需操作Animal类并了解其方法即可操作继承自Animal的对象。也就是说,继承自Animal的Cat和Tiger不需要暴露给使用者,可以隐藏Cat和Tiger的创建过程,不需要被调用者所关心。此时,可以通过模块化和工厂设计模式来实现。
例如,将Animal, Cat, Tiger的实现放入一个动态链接库模块中,并且只向调用者暴露Animal的头文件。而工厂方法设计模式,可以使用一个工厂方法创建具体的对象,返回时只返回基类Animal的指针。本文将从简单工厂开始讨论,然后介绍工厂方法和抽象工厂。
简单工厂是大家最常见的一种实现方法,如下所示:

代码如下:
class AnimalFactory {
public:
enum class AnimalType {
TIGER,
CAT
};</p><pre class="brush:php;toolbar:false;"><code>static Animal* CreateAnimal(const AnimalType type) {
if (AnimalType::TIGER == type) {
return new Tiger;
}
else if (AnimalType::CAT == type) {
return new Cat;
}
return nullptr;
}};
调用方式如下:
Animal<em> pAnimal = AnimalFactory::CreateAnimal(AnimalFactory::AnimalType::TIGER); Attack(pAnimal); pAnimal = AnimalFactory::CreateAnimal(AnimalFactory::AnimalType::CAT); Attack(pAnimal);
然而,这种方式违背了软件开发的开闭原则(Open-Closed Principle, OCP)。如果需要添加一个名为Dog的对象,则需要在CreateAnimal方法中修改分支判断逻辑。简单来说,这种扩展方式破坏了原有逻辑,扩展可能会影响软件的稳定性。
有些人可能不喜欢这种代码方式,但也有人认为这种书写方式比较简单。从个人工程实践经验来看,软件开发设计原则具有很好的指导意义,但并不是所有代码都必须完全符合这些原则。个人的理解如下:
在工程实践中,有时为了让代码完全遵循软件开发设计原则,反而会带来负担,例如过度设计问题。一方面,有些代码模块可能几年都不会被修改扩展;另一方面,当逻辑实现比较简单时,过度设计也会使代码维护者阅读代码更加费劲。毕竟大多数人只是普通的程序员。往往可扩展的代码编写时间更长,但程序员头上的压力还有软件开发时间。对于一般的程序员来说,在规定时间内高质量完成需求是首要任务,此时可能不会完全考虑软件开发设计原则。如果要符合开闭原则,可以实现工厂方法模式,让我们一起来看看。
工厂方法的主要特点是通过继承一个AnimalFactory来实现具体的工厂,例如CatFactory主要负责生产Cat,而TigerFactory主要负责生产Tiger,其类图如下:

代码如下:
class AnimalFactory {
public:
virtual Animal</em> CreateAnimal() = 0;
};</p><p>class CatFactory : public AnimalFactory {
public:
virtual Animal* CreateAnimal() {
return new Cat;
}
};</p><p>class TigerFactory : public AnimalFactory {
public:
virtual Animal<em> CreateAnimal() {
return new Tiger;
}
};调用方式如下:
AnimalFactory</em> pFactory = new TigerFactory; Animal* pAnimal = pFactory->CreateAnimal(); Attack(pAnimal); pFactory = new CatFactory; pAnimal = pFactory->CreateAnimal(); Attack(pAnimal);
可以发现,工厂方法模式如果需要扩展一个新的动物类型,也可以对应扩展一个新的工厂,例如增加一个新的DogFactory继承AnimalFactory来生产Dog,从而符合开闭原则,更加安全地进行扩展。然而,这种方式也可以看出,每增加一个新的动物类型就需要新增一个Factory。个人对这种模式的理解如下:
当动物类型的创建过程并不繁琐时,采用这种方式相较于简单工厂而言会更加繁琐;但当初始化过程较多时,使用工厂方法模式扩展会显得更加清晰。这种设计模式的本身实现是取消了条件判断的逻辑,但实际上是将这个条件判断任务交给了使用者去判断选择哪个工厂。
对于新手来说,可能不太容易理解抽象工厂模式,容易将其与工厂方法模式混淆。工厂方法模式中的每个工厂生产一个动物角色,而在抽象工厂中生产一类动物角色的抽象。一个动物角色比较好理解,就是我们上面的CatFactory生产Cat角色,而TigerFactory生产Tiger角色。一类动物角色,我们可以理解为在游戏中,这些动物角色的攻击性分为普通模式和困难模式。
首先,我们将Tiger分为SimpleModeTiger和HardModeTiger;Cat分为SimpleModeCat和HardModeCat。然后,抽象工厂提供CreateAnimal接口,继承的SimpleModeFactory可以生产简单模式的Cat角色和Tiger角色,继承的HardModeFactory可以生产困难模式的Cat角色和Tiger角色。

实现的代码如下所示:
#include <iostream></p><p>class Animal {
public:
virtual void Attack() = 0;
};</p><p>class AbstractTiger : public Animal {
public:
virtual void Attack() = 0;
};</p><p>class SimpleModeTiger : public AbstractTiger {
public:
virtual void Attack() {
std::cout << "SimpleModeTiger Attack!" << std::endl;
}
};</p><p>class HardModeTiger : public AbstractTiger {
public:
virtual void Attack() {
std::cout << "HardModeTiger Attack!" << std::endl;
}
};</p><p>class AbstractCat : public Animal {
public:
virtual void Attack() = 0;
};</p><p>class SimpleModeCat : public AbstractCat {
public:
virtual void Attack() {
std::cout << "SimpleModeCat Attack!" << std::endl;
}
};</p><p>class HardModeCat : public AbstractCat {
public:
virtual void Attack() {
std::cout << "HardModeCat Attack!" << std::endl;
}
};</p><p>class AbstractAnimalFactory {
public:
virtual Animal* CreateAnimal(AnimalType type) = 0;
};</p><p>class SimpleModeAnimalFactory : public AbstractAnimalFactory {
public:
virtual Animal* CreateAnimal(AnimalType type) {
if (type == AnimalType::TIGER) {
return new SimpleModeTiger;
}
else if (type == AnimalType::CAT) {
return new SimpleModeCat;
}
return nullptr;
}
};</p><p>class HardModeAnimalFactory : public AbstractAnimalFactory {
public:
virtual Animal* CreateAnimal(AnimalType type) {
if (type == AnimalType::TIGER) {
return new HardModeTiger;
}
else if (type == AnimalType::CAT) {
return new HardModeCat;
}
return nullptr;
}
};</p><p>int main() {
// 简单模式
AbstractAnimalFactory<em> pFactory = new SimpleModeAnimalFactory;
Animal</em> pAnimal = pFactory->CreateAnimal(AnimalType::TIGER);
Attack(pAnimal);
pAnimal = pFactory->CreateAnimal(AnimalType::CAT);
Attack(pAnimal);</p><pre class="brush:php;toolbar:false;"><code>// 困难模式
pFactory = new HardModeAnimalFactory;
pAnimal = pFactory->CreateAnimal(AnimalType::TIGER);
Attack(pAnimal);
pAnimal = pFactory->CreateAnimal(AnimalType::CAT);
Attack(pAnimal);}
为了让结构简单,便于读者理解抽象工厂模式以及与工厂方法模式的区别,上述SimpleModeFactory和HardModeFactory使用的是简单工厂的形式实现的。如果需要符合开闭原则,可以再对SimpleModeFactory和HardModeFactory进行工厂方法的实现。可以想象,如果抽象工厂再加上工厂方法,这个类的结构会变得非常庞大,而且这还仅仅是两个游戏角色的描述。因此,笔者认为在进行工程实践时,尽量避免过度设计,有时反而不利于代码阅读,修改也未必简单。需要权衡好工程和理论的平衡点。
参考:
以上就是设计模式之简单工厂,工厂方法和抽象工厂的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号