使用依赖注入创建对象管道(Ninject)

时间:2014-04-10 01:21:00

标签: c# dependency-injection ninject

我在使用依赖注入(DI)决定如何最好地构建双向对象管道时遇到了一些困难。

我目前正在试验Ninject作为DI容器。

实际上它比这更复杂,因为我正在考虑将两个管道与适配器绑定在一起。

这两个管道由(ITransportITransportSink)和(IMessageProcessorIMessageProcessorSink)接口对定义如下:

public interface ITransport {
  void Connect();
  void Disconnect();
  void Send(byte[] buffer)
  void Receive();
}

public interface ITransportSink {
  void OnConnected();
  void OnDisconnected();
  void OnSent();
  void OnReceived(byte[] data);
}

public interface IMessageProcessor {
  void SendMessage(string message);
  void ReceiveMessage();
}

public interface IMessageProcessorSink {
  void OnMessageSent();
  void OnMessageReceived(string message);
}

public class TcpTransport : ITransport {
  public TcpTransport(
    ISocket socket, 
    ITransportSink sink,
    ...
  ) { }
}

public class Program : IMessageProcessorSink {
  void Run() {
    // Set up serializer as an adapter between transports and message processors
    var serializer = new MessageSerializer();
    var tcpTransport = new TcpTransport(socket, serializer);
    serializer.SetTransport(tcpTransport);
    serializer.SetMessageSink(this);
  }

  void OnMessageReceived(string message) {
    Console.Writeline("Received message {0}", message);
  }
}

public class MessageSerializer : ITransportSink, IMessageProcessor {
  public void OnReceived(byte[] data) {
    // Deserializes message and raises IMessageProcessorSink::OnMessageReceived
    var message = Deserialize(data);
    m_processorSink.OnMessageReceived(message);
  }

  public void SendMessage(string message) {
    // Serializes message to byte and calls ITransport::Send
    byte[] data = Serialize(message);
    m_transport.Send(data);
  }
}

var program = new Program();
program.Run();

问题:
如何使用Ninject最好地创建管道线和适配器(MessageSerializer)?

问题(进阶):
现在考虑MessageSerializer连接的管道中可能有多个ITransport和多个IMessageProcessors。

使用:

m_kernel.Get<IEnumerable<ITransport>>() 

可能无法正确处理运输的订货 因此,我现在需要介绍一些新概念:

ITransportPipeline  
ITransportPipelineFactory 
IMessageProcessorPipeline
IMessageProcessorPipelineFactory

安装程序将类似于:

var transportPipelineFactory = m_kernel.Get<ITransportPipelineFactory>();
var messagePipelineFactory = m_kernel.Get<IMessageProcessorPipelineFactory>();

var transportPipeline = transportPipelineFactory.CreatePipeline();
var messageProcessorPipeline = messagePipelineFactory.CreatePipeline();

var serializer = new MessageSerializer();
transportPipeline.Append(serializer);
messageProcessorPipeline.InsertAt(0,serializer);

此时我正在编写如此多的手动接线代码,DI容器似乎没有多大帮助。是否有DI个容器功能或绑定可以帮到这里?

我感觉设计是错误的,或者这不是DI容器要解决的情况。

1 个答案:

答案 0 :(得分:0)

我花了一段时间,但我找到了一种方法让它发挥作用。 诀窍是将配置逻辑包装在更高级别的概念对象构造函数中:

public class AggregatePipeline
{
    private ITransportPipeline m_transportPipelines;
    private IMessageProcessorPipeline m_messagePipeline;
    private MessageSerializer m_serializer;

    public AggregatePipeline(
        ITransportPipeline transportPipeline,
        IMessageProcessorPipeline messagePipeline,
        MessageSerializer serializer)
    {
        transportPipeline.Append(serializer);
        messagePipeline.Prepend(serializer);

        m_transportPipeline = transportPipeline;
        m_messagePipeline = messagePipeline;
        m_serializer = serializer;
    }
}

因为每个项都是构造函数参数,所以不需要对内核进行显式调用。 添加几个绑定:

Bind<AggregatePipeline>().ToSelf()
    .WithConstructorArgument("transportPipeline", (ctx) =>
        {
            return ctx.Kernel.Get<ITransportPipelineFactory>().CreatePipeline();
        })
    .WithConstructorArgument("messagePipeline", (ctx) =>
        {
            return ctx.Kernel.Get<IMessageProcessorPipelineFactory>().CreatePipeline();
        });

Bind<MessageSerializer>().ToSelf();

然后通过内核创建外部对象:

m_kernel.Get<AggregatePipeline>();

似乎解决了没有服务位置反模式的问题。