【问题标题】:How to achieve Loose coupling using Ninject如何使用 Ninject 实现松耦合
【发布时间】:2013-01-11 08:47:47
【问题描述】:

我是 Ninject 的新手。有人可以帮助我实现我想要的。 我会给你我的例子。请帮助我如何使用 NInject 获得松散耦合。

假设我有一个下面给出的界面。

public interface IVehicle
{
 PrintSpecification();
}

现在我有三个实现上述接口的类。它们可能如图所示。

public class Car implements IVehicle
{      
 public void PrintSpecification()
 { Console.WriteLine("Specification for Car");}
}

public class Bus implements IVehicle
{
  public void PrintSpecification()
  { Console.WriteLine("Specification for Bus");}
}

public class Truck implements IVehicle
{
  public void PrintSpecification()
  { Console.WriteLine("Specification for Truck");}
}

现在在我的主程序中,我会有这样的东西。这里我使用 new 运算符创建了CarBusTruck 的三个具体实现。我必须显示所有三辆车的规格。现在我想知道如何编写我的 Ninject 代码,以便不依赖具体类。

Public static void main()
{
  IVehicle v1=new Car();
  IVehicle v2=new Bus();
  IVehicle v3=new Truck();
  v1.PrintSpecification();
  v2.PrintSpecification();
  v3.PrintSpecification();
}

【问题讨论】:

  • 回应是:这取决于您如何在应用程序中的不同实现之间进行选择...

标签: c# ninject loose-coupling


【解决方案1】:

您可以通过这种方式绑定所有规范:

public class AutoModule : NinjectModule
{
    public override void Load()
    {
        Bind<IVehicle>().To<Car>();
        Bind<IVehicle>().To<Bus>();
        Bind<IVehicle>().To<Truck>();
    }
}

在您的应用中:

IKernel kernel = new StandardKernel(new AutoModule());

kernel.Bind<Inspector>().ToSelf();

class Inspector
{
      IVehicle[] vehicles;
      public Inspector(IVehicle[] vehicles)
      {
          this.vehicles=vehicles;
      }
      public void PrintSpecifications()
      {
           foreach(var v in vehicles )
           {
              v.PrintSpecification();
            }
      }
}

//automatic injection in constructor
kernel.Get<Inspector>().PrintSpecifications();

如果您想要某种方式有条件地绑定一个实现,您可以使用

  • 命名绑定
  • 条件绑定
  • 上下文绑定

There is a good documentation inthe NInject wiki.

如果您需要在模块中映射多个类型,请考虑使用一些命名约定并创建一些自动绑定策略。

你也应该在与 IoC 容器解耦方面做一些努力,看看 Composition Root Pattern 是如何工作的。

【讨论】:

  • 感谢您的回复。不过,我还有最后一个概念性问题。使用您的解决方案,我没有在我的 Main 方法中创建具体的 Car、Bus 和 Truck,而是在模块的 Load() 方法中创建了它们。现在我的问题是 Load() 方法中的这些类如何使其松散耦合,因为我仍然必须在某处指定具体的类名。
  • 这次我唯一不用的是“new”操作符。这不会使 AutoModule 与具体类紧密耦合。
  • @user1592389 该模块允许紧密耦合,因为它包含要公开的类型。重要的是您的应用程序与模块分离。我建议你也从 IoC 中解耦。
【解决方案2】:

IVehicle 实现创建具有命名绑定的模块:

public class AutoModule : NinjectModule
{
    public override void Load()
    {
        Bind<IVehicle>().To<Car>().Named("Small");
        Bind<IVehicle>().To<Bus>().Named("Big");
        Bind<IVehicle>().To<Truck>().Named("Huge");
    }
}

并按名称获取您的车辆:

IKernel kernel = new StandardKernel(new AutoModule());
IVehicle v1 = kernel.Get<IVehicle>("Small");
IVehicle v2 = kernel.Get<IVehicle>("Huge");
IVehicle v3 = kernel.Get<IVehicle>("Big");
v1.PrintSpecification();
v2.PrintSpecification();
v3.PrintSpecification();

【讨论】:

  • 这是连接具体方法的正确方法还是您只是提供了替代方法。此外,如果我有 50 种其他类型的接口要连接,我应该在同一个加载方法中完成吗?
  • @user1592389 是的,您应该绑定应用程序所需的所有类型。此外,如果您需要将一种类型绑定到不同的实现,您应该使用命名绑定。
  • @lazyberezovsky 命名绑定不是唯一的方法......这取决于你想要实现的目标。
  • @FelicePollano 同意,但关于示例代码,我认为它最合适
猜你喜欢
  • 1970-01-01
  • 2017-04-11
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
  • 2021-09-11
相关资源
最近更新 更多