依赖注入与工厂类 [英] Dependency injection with factory class

查看:136
本文介绍了依赖注入与工厂类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We have a request based application where requests are executed by sending a command over serial.

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

When data is received indicating a request is to be performed the request is created using a factory class by specifying that requests specific ID.

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

The problem is that each request will have different dependencies depending on the tasks it has to perform and I am looking for the best solution to do this.

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

What is the best way to inject dependencies to requests when dependencies may differ between requests?

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

Is passing a reference to the RequestFactory for every possible request dependancy a bad idea? (We currently have around 20-30 different requests that have around 6 or 7 different dependencies in total)

我的计划解决方案类似于下面, ,或更好的方法?

My planned solution is similar to that below, but is there an easier, or better approach?

谢谢。

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(  );
};


推荐答案

@Lilshieste提出的解决方案有相同的缺陷你的原始实现,你必须手动维护一个switch-heavy语句,甚至最糟糕的是,在@Lilshieste解决方案中你增加了给RequestFactory的参数的工厂数量。

The solution proposed by @Lilshieste has the same flaw of your original implementation, you have to manually maintain a "switch-heavy" statement, even worst, in @Lilshieste solution you have increase the number of factories given as parameter to the RequestFactory.

因为你没有提到任何性能问题,我会建议一个更慢,但更加坚实的解决方案。

Since you don't mentioned any performance issue I'll propose a little slower, but more solid solution.

我不同意这需要聚合,原因是在你的情况下,你只是没有很多依赖,你需要多态行为,它不需要聚合,但构建一个适当的接口来处理。

I do not agree that this need aggregation, the reason is that in your case you just don't have many dependencies, you need polymorphic behaviour, wich does not require aggregation but construction of an appropiate interface to deal with.

观察1:
由于您使用的是C ++ 11,因此使用新的枚举而不是int作为ID(这将导致有用的编译时错误)。

Observation 1: Since you are using C++11, use the new enums instead of "int" for the ID (that will give usefull compile time errors).

观察2:
逆转问题。不要让泛型RequestFactory依赖于具体工厂,而是让ConcreteFactories在RequestFactory中注册自己!

Observation 2: Reverse the problem. Dont let the generic RequestFactory depends on Concrete Factories, instead let ConcreteFactories register themselves in the 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;
    }

};

每个工厂都有相同的接口,因为你做DI,你可能想要管理工厂。只是继承自enable_shared_from_this。

Every Factory have the same Interface, since you are doing DI, you probably want the factory to be managed. Just inherit from enable_shared_from_this.

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();
    }
};

RequestFactory现在没有构造函数依赖关系,还要注意,其接口在2部分,使不同用户的工厂可以做不同的事情。

The RequestFactory has now no constructor dependencies, also note that I broke up its interface in 2 parts so that different users of the factory can do different things.

#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();
    }
};

如果您使用依赖注入框架

现在,连接一切的工作非常简单,以下示例使用 Infectorpp (我写的),你可以与其他框架做类似的事情当然。

now the work to wire up everything is very simple, the following example uses Infectorpp (wich I wrote), you can do similiar things with other frameworks of course.

#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;
}

也考虑为这些工厂创建围绕std :: unique_ptr的对象,而不是一个std :: shared_ptr(如果unique_ptr足够,从不使用std :: shared_ptr)。

Also consider creating objects wrapped around a std::unique_ptr for those factories instead of a std::shared_ptr (if unique_ptr is enough never use std::shared_ptr).

这篇关于依赖注入与工厂类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆