代码之家  ›  专栏  ›  技术社区  ›  LightCC

如何在C中设置DI/IoC和/或工厂模式设计#

  •  1
  • LightCC  · 技术社区  · 8 年前

    我有一个设计,需要SSH连接才能访问命令行界面来运行一些系统/功能级别的测试自动化。可能有几种不同类型的SSH客户端:

    • 与普通C/Bash shell的直接连接
    • 虚拟机内或通过网关服务器等的隧道/转发连接。
    • 需要在登录后从shell启动特定命令行调试接口的连接

    我正在使用SSH。NET开源库作为C#和Visual Studio下的NuGet包,在连接、发出命令和读回StdOut和StdErr响应的简单情况下,一切都正常工作。

    我的问题是,我想在这里实现几个会话/命令层,但不确定如何正确使用接口来实现它们。我想使用DI/IoC来分隔 SshSession SshCommand 层之间以及SSH中的层。净额 SshClient 课堂上,但我如何开始设计?

    我已经阅读了很多关于DI/IoC的解释,并使用IoC容器等实现了一些单元测试,但设置DI的核心方法仍然是不点击。我认为我不需要IoC容器来实现这一点,但可能需要使用工厂模式,甚至一些我仍然不熟悉的其他模式。


    例如,要创建具有不同连接标准的多个客户端类型,我想我需要如下内容:

    • ISshSession
    • SshSessionBase : ISshSession 作为基类
    • 然后创建使用 SshSessionBase

    但是,DI实际上是如何工作的呢?自定义类是否被注入基类的构造函数中 IsshSession 物体?或者我需要另一个使用这些自定义类对象的工厂或执行器类吗?

    我可能把这里的话题搞混了。。我只是缺少一些东西来将我正在阅读的内容转换为实际的实现——感谢您的帮助!

    1 回复  |  直到 8 年前
        1
  •  3
  •   mbnx    8 年前

    我不确定是否理解您的设计,但一般方法可以是:

    1. Connect() Send(ICommand) 方法

    2. 思考设计中其他组件的结构和行为元素,例如命令或记录器或其他任何组件。结果将是某种基类库。

    工厂本身可以实例化具体的类,但您的连接类可以利用基于构造函数的注入来访问其他组件(记录器、助手等),因此您的工厂可以依赖IoC容器,例如:

    使现代化 :正如Michael指出的,将容器传递给工厂可能很方便,但隐藏了工厂的具体依赖关系。虽然可以使用较小的应用程序,但更好的方法是将所有连接类型依赖项传递给实例化具体实例的工厂。

    class StandardConnectionFactory : IConnectionFactory
    {
        private readonly IContainer iocContainer;
    
        public StandardConnectionFactory(IContainer iocContainer) 
        {
            this.iocContainer = iocContainer;
        }
    
        public IConnection Create(string param1, int param2, ...)
        {
             if (...) return iocContainer.Resolve<IFancySshConnection>();
             else return iocContainer.Resolve<IAnotherConnection>();
        }
    } 
    
    1. 如果关于使用哪种连接类型的决定依赖于一些简单的枚举或字符串(例如,用户决定通过命令行参数使用哪种连接),则一些IoC容器(例如Autofac)允许使用名称注册类并使用该名称解析。在这种情况下,您不需要工厂,最终可能会得到以下结果:

    (伪代码)

    // Registration Process
    containerBuilder.Register<FancySshConnection>().For<IConnection>().WithName("ssh");
    containerBuilder.Register<FancyFtpConnection>().For<IConnection>().WitName("ftp");
    
    // Resolve
    var connection = container.ResolveByName("ftp")
    
    1. 当您完成通过显式工厂(3)或某些内置实例化(4)实例化连接的方法时,IoC容器已知的连接类型的依赖项将自动注入。例如,上述调用 iocContainer.Resolve<IFancySshConnection>(); 将实例化具体的连接类型,查看其构造函数,尝试解析每个参数,注入它们,等等。只要找到以前注册过的依赖项,它就会爬上依赖树。

    2. 如果事情变得更大、更复杂,你最终可能会有很多注册。一些IoC容器(我坚持使用Autofac示例,因为我非常喜欢Autofac)提供了一种将注册拆分为模块的简单方法。这允许将注册过程分发到不同的程序集。