- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个关于使用多态类进行依赖注入(inject)的最佳实践的问题。我是 C++ 的新手,所以如果这是一个明显的问题,请原谅我。假设我有一个 Runner 类,它需要接收两个对象,一个 Logger 和一个 Worker。 Logger 是一个抽象类,有两个子类,比如 FileLogger 和 SocketLogger。同样,Worker 是一个抽象类,有两个子类,比如 ApproximateWorker 和 CompleteWorker。
Runner 类将从 main() 创建,并将基于配置文件或类似文件创建 Logger 和 Worker。我已经阅读了很多有关 SO 和其他地方的资料,普遍的看法似乎是更喜欢堆栈分配的对象并通过引用传递它们。但是,我不太确定如何管理动态创建这样的对象。如果使用堆分配的对象,我可以这样做:
Logger* log;
Worker* worker;
if (/*user wants a file logger*/ {
log = new FileLogger();
} else {
log = new SocketLogger();
}
if (/* user wants an approximate worker*/) {
worker = new ApproximateWorker();
} else {
worker = new CompleteWorker();
}
Runner runner = Runner(log, worker);
runner.run();
因为我只是将指针存储在堆栈上,所以我可以独立处理 Logger 和 Worker 的不同情况。如果使用堆栈分配的对象,我唯一能想到的就是做类似的事情:
if (/*file logger and approx worker*/) {
FileLogger log();
ApproximateWorker worker();
Runner runner = Runner(log, worker);
} else if (/*file logger and complete worker*/) {
FileLogger log();
CompleteWorker worker();
Runner runner = Runner(log, worker);
} else if (/*socket logger and approx worker*/) {
SocketLogger log();
ApproximateWorker worker();
Runner runner = Runner(log, worker);
} else {
SocketLogger log();
CompleteWorker worker();
Runner runner = Runner(log, worker);
}
显然,如果要传入两个以上的对象,或者每个对象有两个以上的子类,这很快就会变得荒谬。我的理解是对象切片将阻止您执行类似于第一个代码段的操作。
我在这里遗漏了什么明显的东西吗?或者这是使用动态内存的情况(当然还有智能指针)?
最佳答案
如果 Runner
将以多态方式使用这些对象(通过基类接口(interface)访问派生对象),您应该将指针或引用传递给它。栈上和堆上的变量各有利弊。没有普遍的规则说一个比另一个更受欢迎。
还有一点,abstract factory pattern可能适合你的情况。它将 WHAT(使用的对象的确切类型)与 HOW(使用这些对象)分开。这一切都是关于封装更改。
// Factory.h
class tAbstractFactory
{
public:
virtual Logger* getLogger() = 0;
virtual Worker* getWorker() = 0;
};
template<typename loggerClass, typename workerClass>
class tConcreteFactory: public tAbstractFactory
{
public:
loggerClass* getLogger() { return new loggerClass; }
workerClass* getWorker() { return new workerClass; }
};
// Runner.h
class Runner
{
public:
Runner(tAbstractFactory &fa)
{
m_logger = fa.getLogger();
m_worker = fa.getWorker();
}
private:
Logger *m_logger;
Worker *m_worker;
};
// Factory.cpp
tAbstractFactory &getFactory(int sel)
{
if (sel == 1)
{
static tConcreteFactory<FileLogger, ApproximateWorker> fa;
return fa;
}
else if (sel == 2)
{
static tConcreteFactory<FileLogger, CompleteWorker> fa;
return fa;
}
else if (sel == 3)
{
static tConcreteFactory<SocketLogger, ApproximateWorker> fa;
return fa;
}
else
{
static tConcreteFactory<SocketLogger, CompleteWorker> fa;
return fa;
}
}
// Client.cpp
Runner runner(fac);
编辑:
我至少看到两个好处:
当您添加新案例或更改具体 Logger/Worker 的类型时,Client.cpp 不会受到影响。也就是说,您限制 Factory.cpp 内部的更改,以便客户端逻辑(实际上使用创建的对象)保持不变。
Runner
仅编程为工厂界面。依赖于 Runner
接口(interface)的客户端不会受到 Logger
、Worker
等变化的影响。
就个人而言,不将此模式用于小型代码库是完全可以的。在类/文件之间存在大量依赖关系的大型项目中,它会对编译时间和可伸缩性产生影响。
关于C++依赖注入(inject)多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31623384/
我来自 Asp.Net 世界,试图理解 Angular State 的含义。 什么是 Angular 状态?它类似于Asp.Net中的ascx组件吗?是子页面吗?它类似于工作流程状态吗? 我听到很多人
我一直在寻找 3 态拨动开关,但运气不佳。 基本上我需要一个具有以下状态的开关: |开 |不适用 |关 | slider 默认从中间开始,一旦用户向左或向右滑动,就无法回到N/A(未回答)状态。 有人
我是一名优秀的程序员,十分优秀!