C++ 工厂类的依赖注入

C++ 工厂类的依赖注入,c++,c++11,dependency-injection,C++,C++11,Dependency Injection,我们有一个基于请求的应用程序,其中通过串行通信发送命令来执行请求 当接收到指示要执行请求的数据时,通过指定请求的特定ID,使用factory类创建请求 问题是,每个请求都有不同的依赖关系,这取决于它必须执行的任务,我正在寻找最好的解决方案 当请求之间的依赖关系可能不同时,向请求注入依赖关系的最佳方法是什么 为每个可能的请求依赖性传递对RequestFactory的引用是一个坏主意吗?(我们目前有大约20-30个不同的请求,总共有大约6或7个不同的依赖项) 我计划的解决方案与下面的类似,但是否有更

我们有一个基于请求的应用程序,其中通过串行通信发送命令来执行请求

当接收到指示要执行请求的数据时,通过指定请求的特定ID,使用factory类创建请求

问题是,每个请求都有不同的依赖关系,这取决于它必须执行的任务,我正在寻找最好的解决方案

当请求之间的依赖关系可能不同时,向请求注入依赖关系的最佳方法是什么

为每个可能的请求依赖性传递对
RequestFactory
的引用是一个坏主意吗?(我们目前有大约20-30个不同的请求,总共有大约6或7个不同的依赖项)

我计划的解决方案与下面的类似,但是否有更简单或更好的方法

谢谢

class Request;
class RequestOne;
class RequestTwo;

class RequestFactory
{
public:
  RequestFactory( /* Dependencies for RequestOne and RequestTwo */ )
  {
    // Keep reference to dependencies
  }

  std::shared_ptr< Request > create( int id )
  {
    std::shared_ptr< Request > request;

    switch ( id )
    {
    case 1:
      request = std::make_shared< RequestOne >( /* RequestOne Dependencies */ );
      break;
    case 2:
      request = std::make_shared< RequestTwo >( /* RequestTwo Dependencies */ );
      break;
    }

    return request;
  }
};

class Request
{
public:
  virtual ~Request(  );
  virtual void process(  ) = 0;
};

class RequestOne : public Request
{
public:
  RequestOne( /* RequestOne Dependencies */ )
  virtual ~RequestOne(  );
  virtual void process(  );
};

class RequestTwo : public Request
{
public:
  RequestTwo( /* RequestTwo Dependencies */ );
  virtual ~RequestTwo(  );
  virtual void process(  );
};
类请求;
第一类;
第二类;
类请求工厂
{
公众:
RequestFactory(/*RequestOne和RequestTwo的依赖项*/)
{
//保持对依赖项的引用
}
std::shared_ptrcreate(int-id)
{
std::共享的ptrRequest;
开关(id)
{
案例1:
request=std::使_共享(/*RequestOne依赖项*/);
打破
案例2:
request=std::使_共享(/*RequestTwo依赖项*/);
打破
}
返回请求;
}
};
类请求
{
公众:
虚拟请求();
虚空进程()=0;
};
类RequestOne:公共请求
{
公众:
RequestOne(/*RequestOne依赖项*/)
虚拟的~RequestOne();
虚空进程();
};
类request2:公共请求
{
公众:
RequestTwo(/*RequestTwo Dependencies*/);
虚拟~RequestTwo();
虚空进程();
};

听起来您主要关心的是需要提供给
RequestFactory
(即所有产品的依赖项的联合)的构造函数参数的数量。处理这种情况的方法与处理类具有大量依赖项的其他类的方法相同:为类识别新的协作者

当一个类聚集越来越多的依赖项/协作者时,一些依赖项之间往往会出现模式。这些模式几乎总是表示一些以前未被识别的抽象。如果您可以在这样一个抽象上放置一个名称,那么您可以重构该类以使用它来代替“相关”依赖项

Mark Seemann将此称为

您的
RequestFactory
似乎是一个很好的选择。考虑一下,如果<代码> RequestFactory < /C> >类与其他两个类协作:
class Request;
class RequestOne;
class RequestTwo;

class RequestOneFactory
{
public:
    virtual std::shared_ptr< RequestOne > CreateRequest(/* RequestOne Dependencies */) = 0;
};

class RequestTwoFactory
{
public:
    virtual std::shared_ptr< RequestTwo > CreateRequest(/* RequestTwo Dependencies */) = 0;
};

class RequestFactory
{
public:
  RequestFactory(std::shared_ptr< RequestOneFactory > requestOneFactory, std::shared_ptr< RequestTwoFactory > requestTwoFactory)
  {
    // Keep reference to collaborating factories
  }

  std::shared_ptr< Request > create( int id )
  {
    std::shared_ptr< Request > request;

    switch ( id )
    {
    case 1:
      request = requestOneFactory->CreateRequest();
      break;
    case 2:
      request = requestTwoFactory->CreateRequest();
      break;
    }

    return request;
  }
};
类请求;
第一类;
第二类;
类RequestOneFactory
{
公众:
虚拟std::shared_ptrCreateRequest(/*RequestOne依赖项*/)=0;
};
类RequestTwoFactory
{
公众:
虚拟std::shared_ptrCreateRequest(/*RequestTwo Dependencies*/)=0;
};
类请求工厂
{
公众:
RequestFactory(std::shared_ptrRequestOneFactory,std::shared_ptrRequestTwoFactory)
{
//参考合作工厂
}
std::shared_ptrcreate(int-id)
{
std::共享的ptrRequest;
开关(id)
{
案例1:
request=requestOneFactory->CreateRequest();
打破
案例2:
request=requestTwoFactory->CreateRequest();
打破
}
返回请求;
}
};
从这个角度来看,我们可能开始怀疑
RequestFactory
是否真的承担了多重责任:

  • 确定要创建的请求类型
  • 创建该类型的请求
  • 通过重构代码,
    RequestFactory
    维护第一责任,同时将其他责任委托给协作类


    注意:使用上述方法,抽象工厂可能会受到具体请求类的严重影响,而具体请求类可能会影响抽象工厂。然而,我怀疑
    RequestOne
    RequestTwo
    本身可能代表不同的抽象,这将使抽象工厂的引入更具逻辑性。

    由@Lilshieste提出的解决方案与原始实现有相同的缺陷,您必须手动维护一个“重开关”语句,甚至最糟糕的是,在@Lilshieste解决方案中,您增加了作为RequestFactory参数提供的工厂数量

    因为您没有提到任何性能问题,所以我将建议稍微慢一点,但更可靠的解决方案

    我不同意这需要聚合,原因是在您的情况下,您没有太多的依赖关系,您需要多态行为,它不需要聚合,但需要构造适当的接口来处理

    观察1: 因为您使用的是C++11,所以使用新的枚举而不是ID的“int”(这将产生有用的编译时错误)

    观察结果2: 扭转这个问题。不要让通用RequestFactory依赖于具体工厂,而是让具体工厂在RequestFactory中注册自己

    class RequestOneFactory: public virtual AbstractRequestFactory{
        //note: no member variables! 
    public:
        RequestOneFactory( std::shared_ptr<RequestFactorySupplier> factory){
            factory->register( getptr(),ID);
        }
    
        std::shared_ptr< Request> create() const{
            std::shared_ptr< Request> request =
                std::make_shared< RequestOne>( /* Dependencies*/);
            return request;
        }
    
    };
    
    class RequestOneFactory:公共虚拟抽象RequestFactory{
    //注意:没有成员变量!
    公众:
    RequestOneFactory(标准::共享工厂){
    工厂->寄存器(getptr(),ID);
    }
    std::shared_ptrcreate()常量{
    std::共享请求=
    std::使_共享(/*依赖项*/);
    返回请求;
    }
    };
    
    每个工厂都有相同的接口,因为您正在进行DI,所以您可能希望对工厂进行管理。只需从中继承,即可从中启用\u共享\u

    class AbstractRequestFactory: std::enable_shared_from_this< AbstractRequestFactory>{
    public:
        virtual ~AbstractRequestFactory(){}
    
        virtual std::shared_ptr< Request> create() const = 0;
    
        std::shared_ptr<AbstractRequestFactory> getptr() {
            return shared_from_this();
        }
    };
    
    类AbstractRequestFactory:std::en
    #include <unordered_map>
    #include <RequestFactorySupplier.hpp>
    #include <RequestFactoryUser.hpp>
    #include <AbstractRequestFactory.hpp>
    
    class RequestFactory: public virtual RequestFactorySupplier
                         ,public virtual RequestFactoryUser{
        //associative container.
        std::unordered_map< RequestID, std::shared_ptr< AbstractRequestFactory>> map;
    
    public:
        RequestFactory()=default;
        ~RequestFactory()=default;
    
        //IMPLEMENTS: RequestFactorySupplier
        virtual void register( std::shared_ptr< AbstractRequestFactory> fac, RequestID id){
             if(map.find(id)!=map.end()){
                  //ID already used.. throw error, assert(false), what you want.
             }
             map[id] = fac;
        }
    
        //IMPLEMENTS: RequestFactoryUser
        virtual std::shared_ptr< Request> create(RequestID id){
             if(map.find(id)==map.end())
                  throwSomething(); //No factory for such ID
             return map[id]->create();
        }
    };
    
    #include <Infectorpp/InfectorContainer.hpp>
    
    int main(){
    Infector::Container ioc;
    
    //register generic factory with 2 interfaces
    ioc.bindSingleAs<RequestFactory,    RequestFactorySupplier,RequestFactoryUser>();
    
    //for each concrete factory register it
    ioc.bindSingleAsNothing<RequestOneFactory>();
    ioc.bindSingleAsNothing<RequestTwoFactory>();
    //...
    
    //wire the generic factory
    ioc.wire<RequestFactory>();
    
    //wire the factories (dependencies injected here)
    ioc.wire<RequestOneFactory,    RequestFactorySupplier>();
    ioc.wire<RequestTwoFactory,    RequestFactorySupplier>();
    //...
    
    //build the factories (let them register in RequestFactorySupplier)
    {
        ioc.buildSingle<RequestOneFactory>();
        ioc.buildSingle<RequestTwoFactory>(); 
        //you will not have references to them but RequestFactory will: Good!
    }
    
    //Your classes can use RequestFactoryUser to create RequestObjects.
    
    //application run!
    
    return 0;
    }