草庐IT

C++依赖注入(inject)多态性

coder 2024-02-23 原文

我有一个关于使用多态类进行依赖注入(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);

编辑:

我至少看到两个好处:

  1. 当您添加新案例或更改具体 Logger/Worker 的类型时,Client.cpp 不会受到影响。也就是说,您限制 Factory.cpp 内部的更改,以便客户端逻辑(实际上使用创建的对象)保持不变。

  2. Runner 仅编程为工厂界面。依赖于 Runner 接口(interface)的客户端不会受到 LoggerWorker 等变化的影响。

就个人而言,不将此模式用于小型代码库是完全可以的。在类/文件之间存在大量依赖关系的大型项目中,它会对编译时间和可伸缩性产生影响。

关于C++依赖注入(inject)多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31623384/

有关C++依赖注入(inject)多态性的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. ruby - 这个 ruby​​ 注入(inject)魔术是如何工作的? - 2

    我今天看到了一个ruby​​代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem

  7. ruby - 有什么方法可以告诉 sidekiq 一项工作依赖于另一项工作 - 2

    有什么方法可以告诉sidekiq一项工作依赖于另一项工作,并且在后者完成之前无法开始? 最佳答案 仅使用Sidekiq;答案是否定的。正如DickieBoy所建议的那样,您应该能够在依赖作业完成时将其启动。像这样。#app/workers/hard_worker.rbclassHardWorkerincludeSidekiq::Workerdefperform()puts'Doinghardwork'LazyWorker.perform_async()endend#app/workers/lazy_worker.rbclassLaz

  8. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  9. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

    我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

  10. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

随机推荐