·
日常编程 ·
136405
工厂方法模式通过虚函数将对象创建延迟到子类,实现解耦;C++中以抽象工厂定义接口,具体工厂创建具体产品,客户端仅依赖抽象,符合开闭原则,便于扩展与维护。
工厂方法模式是一种创建型设计模式,它把对象的创建过程封装到子类中,让父类不依赖具体对象的类型。在C++中,通过虚函数定义创建对象的接口,由派生类决定实例化哪个类,从而实现对象创建的解耦。
工厂方法模式的核心思想
定义一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类。
关键点:
- 有一个抽象工厂基类,声明一个创建对象的虚函数
- 每个具体工厂继承基类,实现自己的对象创建逻辑
- 客户端代码只依赖抽象接口,不关心具体类型
基本实现结构
以生产不同类型的“产品”为例:
#include
#include
// 产品抽象基类
class Product {
public:
virtual ~Product() = default;
virtual void use() const = 0;
};
// 具体产品A
class ConcreteProductA : public Product {
public:
void use() const override {
std::cout << "使用产品 A\n";
}
};
// 具体产品B
class ConcreteProductB : public Product {
public:
void use() const override {
std::cout << "使用产品 B\n";
}
};
// 工厂基类 - 定义创建产品的接口
class Factory {
public:
virtual ~Factory() = default;
virtual std::unique_ptr createProduct() const = 0;
};
// 具体工厂A - 创建产品A
class ConcreteFactoryA : public Factory {
public:
std::unique_ptr createProduct() const override {
return std::make_unique();
}
};
// 具体工厂B - 创建产品B
class ConcreteFactoryB : public Factory {
public:
std::unique_ptr createProduct() const override {
return std::make_unique();
}
};
使用示例
客户端通过工厂接口创建对象,无需知道具体类名:
int main() {
// 可以根据配置或条件选择工厂
std::unique_ptr factory;
// 假设条件判断使用哪种工厂
bool useTypeA = true;
if (useTypeA) {
factory = std::make_unique();
} else {
factory = std::make_unique();
}
// 创建产品
auto product = factory->createProduct();
product->use(); // 输出:使用产品 A
return 0;
}
优势与适用场景
工厂方法模式在C++中特别适合以下情况:
-
避免在代码中写死 new 操作:将对象创建集中管理
-
扩展性好:新增产品类型时,只需添加新的工厂类,不修改已有代码
-
符合开闭原则:对扩展开放,对修改关闭
-
解耦客户端与具体类:客户端只依赖抽象接口
基本上就这些。工厂方法模式用虚函数把对象创建封装起来,让程序更灵活,也更容易维护。不复杂但容易忽略细节,比如记得把析构函数设为虚函数,避免资源泄漏。
以上就是C++工厂方法模式 对象创建接口封装的详细内容,更多请关注骃骐网【www.myinqi.com】。
本文介绍一种优雅的 python 设计模式:通过私有属性 + 只读属性 + 显式 update() 方法,确保对象状态变更时回调函数(如数据校验、视图刷新等)仅被触发一次,避免重复计算,同时保持 ide 类型提示与代码可维护性。 本文介绍一种优雅的 python 设计模式:通过私有属性 + 只读属性 + 显式 update() 方法,确保对象状态变更时回调函数(如数据校验、视图刷新等)仅被触发一次...
字典的key不能是列表,因为列表是可变对象,不可哈希,执行hash([1,2])会直接抛出TypeError;而字典依赖哈希值快速查找,若键可变会导致哈希表失效。 为什么字典的 key 不能是列表 因为 dict 内部依赖哈希值做快速查找,而列表是可变对象,hash([]) 会直接抛出 TypeError: unhashable type: 'list'。只要对象在插入后可能被修改(比如调用 .a...
Flask 中 g 对象仅在请求上下文中有效,生命周期始于 @app.before_request、终于响应发出,不可跨请求共享;模板中无法直接访问 g,需用 add_template_global 注册 Jinja2 全局变量;跨请求状态应使用 session 或 Redis,避免 g 名冲突需加前缀。 Flask 里没有真正意义上的“全局变量”,所有看似全局的变量都绑定在上下文里;直接用模块级...
gc.collect()后对象仍在gc.garbage中,说明它被判定为不可回收的循环引用;需先启用gc.DEBUG_SAVEALL,再调用gc.collect()触发保存,且gc.garbage需手动清空以防累积。 gc.collect() 后对象还在 gc.garbage 里,说明它被判定为不可回收的循环引用 Python 的 gc 模块默认不暴露循环引用细节,但一旦你调用 gc.collec...
用flasgger是Flask项目集成Swagger文档最轻量靠谱的选择;它通过装饰器和docstring生成可交互UI,需安装pyyaml并调用Swagger(app),注意YAML语法、definitions引用及类型书写规范。 Flask 项目里加 Swagger 文档,flasgger 是最轻量靠谱的选择 直接说结论:用 flasgger 比手写 OpenAPI YAML、或套 apisp...
FastAPI 路由返回空对象 {} 是因同步数据库操作与异步路由不匹配导致的 ORM 实例延迟加载失效;根本原因是未正确使用异步数据库会话方法(如 await db.scalar()),导致返回对象在序列化前已脱离会话上下文。 fastapi 路由返回空对象 `{}` 是因同步数据库操作与异步路由不匹配导致的 orm 实例延迟加载失效;根本原因是未正确使用异步数据库会话方法(如 `await d...
copy.copy有时没用是因为它只做浅拷贝,不递归复制嵌套的可变子对象,导致新旧对象共享内部可变元素,修改一方会影响另一方。 copy.copy 为什么有时没用? 因为 copy.copy 只做浅拷贝,它只复制对象本身,不递归复制其内部的可变子对象。如果你的对象里嵌套了 list、dict、自定义类实例等,这些子对象在新旧对象中仍共享同一内存地址——改一个,另一个跟着变。 常见错误现象:– 修改...
直接用pika封装而非Celery,因后者抽象过深、依赖繁重;pika更轻量可控,但需自行实现连接池、重连、消息确认等关键逻辑。 为什么不用 Celery 而直接用 pika 封装? 因为 Celery 的抽象层会掩盖连接管理、重试逻辑和消息确认细节,而你只需要发几条任务、或做简单异步通知,又不想引入 celery、kombu、redis 或 eventlet 这类依赖。这时候直接用 pika 更...
sgqlc 与 pytest 结合测试的核心难点在于上下文缺失、类型校验绕过和响应误判;关键实践是用 sgqlc-codegen 同步最新 schema 并提交 Git,测试中通过 Operation 和生成类型类构造合法 query,用 op.variables 提取变量,function 级 fixture 管理 client,独立构造 Operation 避免污染。 直接用 sgqlc 写 ...
本文介绍如何为接受任意JSON可序列化输入的函数设计精确、安全且符合mypy规范的类型提示,解决Union[List[Any], Dict[Any, Any]]不完整、禁用Any及递归类型声明等核心问题。 本文介绍如何为接受任意json可序列化输入的函数设计精确、安全且符合mypy规范的类型提示,解决`union[list[any], dict[any, any]]`不完整、禁用`any`及递归类...