使用部分共享界面组织对象
Organizing objects with partially shared interface
我最近遇到了一些我认为可以用不同设计清理的情况,但我不知道任何适合的模式。
在所有这些情况下,我有几个类部分共享一个 API。例如,记录器类:
struct ILogger { virtual void log(string msg) = 0; };
struct StdOutLogger : public ILogger {
void log(string msg) override; // Log to stdout
};
struct FileLogger : public ILogger {
void log(string msg) override; // Log to file
};
struct GuiLogger : public ILogger {
void log(string msg) override; // Log to GUI
void draw();
void clear();
};
或者也许:
struct Graphic {
virtual void draw();
virtual void setPosition();
// etc.
};
struct AnimatedGraphic : public Graphic {
void draw() override;
void start();
void stop();
void setLooping(bool loop);
};
现在,根据谁拥有这些对象,我可能有一个指向公共接口的引用/指针容器:
class LogManager {
std::vector<std::unique_ptr<ILogger>> _loggers;
// ...
};
或者我可能会将类型分开,并在运行时选择使用哪一个:
// This is already starting to get messy
class SomethingWithGraphic {
std::unique_ptr<Graphic> _graphic;
std::unique_ptr<AnimatedGraphic> _animatedGraphic;
// ...
};
第一个解决方案很好,直到我需要开始使用不属于通用接口的功能。 第二种解决方案允许我选择我需要的解决方案,但它容易出错,并且到处都需要丑陋的分支。
我想出了几个替代解决方案,但我还没有找到一个真正感觉正确的解决方案。
保留一个拥有的容器,并通过不同的接口创建指向拥有对象的其他容器。 (要求容器保持同步)
将所有函数添加到接口,但对于不需要额外函数的对象,将实现留空。 (这些功能实际上不属于该接口的一部分)
存储所有潜在类型的变体。 (感觉像黑客,需要到处都是访客)
使用记录器示例:
//// 1 ////
struct IDrawable {
virtual void draw() = 0;
virtual void clear() = 0;
};
std::vector<std::unique_ptr<ILogger>> _loggers;
std::vector<IDrawable*> _drawableLoggers;
//// 2 ////
struct ILogger {
virtual void log(string msg) = 0;
virtual void draw() {};
virtual void clear() {};
};
struct StdOutLogger : public ILogger {
void log(string msg) override; // Log to stdout
};
struct FileLogger : public ILogger {
void log(string msg) override; // Log to file
};
struct GuiLogger : public ILogger {
void log(string msg) override; // Log to GUI
void draw() override;
void clear() override;
};
//// 3 ////
std::vector<std::variant<StdOutLogger, FileLogger, GuiLogger>> _loggers;
我认为#1似乎是最正确的,但仍然不是最好的。
有谁知道任何模式或结构可以清理它?
一个可行的方法:您可以使用指向接口的指针或引用向量,并为您希望从一个实例中获取其实际类型并调用不属于公共接口的方法的所有情况实现访问者模式。
下面是一个最小的工作示例:
#include<iostream>
#include<memory>
#include<vector>
struct Visitor;
struct Interface {
virtual void method() = 0;
virtual void accept(Visitor &) = 0;
};
struct A: Interface {
void method() override { std::cout << "A::method" << std::endl; }
void f() { std::cout << "A::f" << std::endl; }
void accept(Visitor &) override;
};
struct B: Interface {
void method() override { std::cout << "B::method" << std::endl; }
void g() { std::cout << "B::g" << std::endl; }
void accept(Visitor &) override;
};
struct Visitor {
void visit(A &a) { a.f(); }
void visit(B &b) { b.g(); }
};
void A::accept(Visitor &v) { v.visit(*this); }
void B::accept(Visitor &v) { v.visit(*this); }
int main() {
std::vector<std::unique_ptr<Interface>> vec;
vec.push_back(std::make_unique<A>());
vec.push_back(std::make_unique<B>());
Visitor visitor;
for(auto &&i: vec) {
i->method();
i->accept(visitor);
}
}
相关文章:
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 将对象数组的引用传递给函数
- 你能重载对象变量名本身返回的内容吗
- C++使用整数的压缩数组初始化对象
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 将对象移动到std::shared_ptr
- 代理对象的常量正确性
- 提升 ASIO 无法识别计时器对象
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 如何返回一个类的两个对象相加的结果
- 使用std::函数映射对象方法
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 如何在C++命令行界面程序中运行 COM (.ocx) 对象.(VS2017)
- 使用部分共享界面组织对象
- 提升shared_ptr界面/对象