对象工厂:原理、实现与应用
立即解锁
发布时间: 2025-08-21 01:42:10 阅读量: 1 订阅数: 4 


现代C++设计:泛型编程与设计模式的应用
# 对象工厂:原理、实现与应用
## 1. 动态对象创建方案
在传统的对象创建方式中,可能会依赖大型的 `switch` 语句,但现在我们有了一种动态方案。每个类型的对象都可以向工厂进行自我注册,这将责任从集中的地方转移到了每个具体的类上。当定义一个新的 `Shape` 派生类时,只需添加文件,而无需修改现有文件。以下是一个简单的代码示例:
```cpp
if (i == callbacks_.end())
{
// not found
throw std::runtime_error("Unknown Shape ID");
}
// Invoke the creation function
return (i->second)();
```
## 2. 类型标识符管理
### 2.1 问题与挑战
类型标识符的管理是一个关键问题。添加类型标识符需要一定的规范和集中控制。每次添加新的形状类时,必须检查所有现有的类型标识符,以确保新添加的标识符不会与它们冲突。如果存在冲突,第二次使用相同 ID 调用 `RegisterShape` 将会失败,从而无法创建该类型的对象。
### 2.2 解决方案
- **使用字符串作为类型标识符**:可以将类型标识符存储为字符串,并约定每个类由其名称表示,例如 `Line` 的标识符是 `"Line"`,`Polygon` 的标识符是 `"Polygon"`。由于类名是唯一的,这样可以最大程度地减少名称冲突的可能性。
- **使用 `std::type_info`**:`std::type_info` 是 C++ 提供的运行时类型信息(RTTI)的一部分。可以通过对类型或表达式调用 `typeid` 运算符来获取 `std::type_info` 的引用。`std::type_info` 提供了一个 `name` 成员函数,返回一个指向人类可读类型名称的 `const char*`。然而,这种方法并不适用于所有 C++ 编译器实现,因为 `type_info::name` 的定义仅适用于调试目的,不能保证字符串是实际的类名,也不能保证字符串在整个应用程序中是唯一的,甚至不能保证每次运行应用程序时 `typeid(Line).name()` 指向相同的字符串。
- **使用唯一值生成器**:一种分散式的解决方案是使用唯一值生成器,如随机数或随机字符串生成器。每次向程序中添加新类时,使用该生成器生成一个随机值,并将其硬编码在源文件中,且不再更改。
### 2.3 结论
类型标识符管理并非对象工厂本身的职责。由于 C++ 无法保证唯一、持久的类型 ID,类型 ID 管理成为了一个额外的语言问题,必须由程序员来处理。
## 3. 通用对象工厂
### 3.1 涉及元素
- **具体产品**:工厂以对象的形式交付某种产品。
- **抽象产品**:产品继承自一个基类型(在示例中为 `Shape`)。产品是类型属于某个层次结构的对象,该层次结构的基类型就是抽象产品。工厂以多态的方式工作,返回一个指向抽象产品的指针,而不透露具体产品类型的信息。
- **产品类型标识符**:用于标识具体产品类型的对象。由于 C++ 的静态类型系统,创建产品时必须有类型标识符。
- **产品创建器**:专门用于创建一种特定类型对象的函数或仿函数。我们使用函数指针来建模产品创建器。
### 3.2 通用工厂实现
```cpp
template
<
class AbstractProduct,
typename IdentifierType,
typename ProductCreator
>
class Factory
{
public:
bool Register(const IdentifierType& id, ProductCreator creator)
{
return associations_.insert(
AssocMap::value_type(id, creator)).second;
}
bool Unregister(const IdentifierType& id)
{
return associations_.erase(id) == 1;
}
AbstractProduct* CreateObject(const IdentifierType& id)
{
typename AssocMap::const_iterator i =
associations_.find(id);
if (i != associations_.end())
{
return (i->second)();
}
handle error
}
private:
typedef std::map<IdentifierType, AbstractProduct>
AssocMap;
AssocMap associations_;
};
```
### 3.3 错误处理
当在工厂中未找到注册的创建器时,有多种处理方式,如抛出异常、返回空指针、终止程序、动态加载库并重新尝试操作等。具体的决策取决于具体情况。为了让用户能够自定义错误处理行为,并提供合理的默认行为,将错误处理代码从 `CreateObject` 成员函数中提取出来,放到一个单独的 `FactoryError` 策略中。
```mermaid
graph TD;
A[开始] --> B[查找关联];
B --> C{是否找到};
C -- 是 --> D[调用创建器];
C -- 否 --> E[调用错误处理策略];
D --> F[返回对象指针];
E --> F;
F --> G[结束];
```
### 3.4 默认错误处理实现
```cpp
template <class IdentifierType, class ProductType>
class DefaultFactoryError
{
public:
class Exception : public std::exception
{
public:
Exception(const IdentifierType& unknownId)
: unknownId_(unknownId)
{
}
virtual const char* what()
{
return "Unknown object type passed to Factory.";
}
const IdentifierType GetId()
{
return unknownId_;
};
private:
IdentifierType unknownId_;
};
protected:
StaticProduc
```
0
0
复制全文
相关推荐










