0

我有一种情况,我试图让我的模型和实现尽可能松散耦合,但是我面临的情况是耦合可能比我想要的更接近。

我有一系列“模型”类,所有实现接口。此外,我还有“数据访问”类,它们提供了许多函数,其中之一是将整数查找值解码为其完整的“对象”表示。

在我的模型类中,我想提供对这些解码值的访问,而不需要模型知道数据访问类。

一个简化的例子是:

/// Core classes --

class Car : ICar
{
    public int MakeId { get {...} set { ... } }

    public IMakeInfo Make { get {...} }

    public string Registration { get { ... } set { ... } }

    public int CurrentOwnerId { get { ... } set { ... } }

    public IPerson CurrentOwner { get { ... } }
}

class MakeInfo : IMakeInfo
{
    public string Name { ... }
    public int Id { ... }
    public decimal Weight { ... }
    // etc etc
}

/// Data Access Classes --

class ResolveMake 
{
    public IMakeInfo GetMakeInfo(int id)
    { 
        // Implementation here...
    }

}

如何使Car该类能够将IMakeInfo对象提供给任何消费类而不直接使其知道 ResolveMake 类?在实际实例中,我使用的 Car 类与 ResolveMake 类不在同一个命名空间中,并且它不包含对它的任何实例的引用。

我的一些选择:

  • 实现一个Car可以提供GetMakeInfo方法实例的委托。
  • 某种依赖注入
  • 将 Car 紧密耦合到 ResolveMake 并完成它。
  • 还有其他选择吗?

欢迎任何建议!

4

5 回答 5

1

扩展方法?

namespace CarStuff
{
   class Car : ICar
   {
      public int MakeId { get {...} set { ... } }
      // no Make property...
      public string Registration { get { ... } set { ... } }
      public int CurrentOwnerId { get { ... } set { ... } }
      public IPerson CurrentOwner { get { ... } }
   }
}


namespace MakeExts
{
   class ResolveMake
   {
      public static IMakeInfo Make(this Car myCar)
      {
         //implementation here
      }
   }
}

别处:

using MakeExts;

Car c = new Car();
Console.WriteLine(c.Make().ToString());

编辑:要在 .NET 2.0 中使用扩展方法,您需要以下内容:

基本上,一个类包含:

namespace System.Runtime.CompilerServices 
{ 
   class ExtensionAttribute : Attribute
   {
   }
 }

以及散布在相关地方的“使用 System.Runtime.CompilerServices”。

于 2009-06-22T08:32:44.337 回答
1

对我来说,这听起来像是依赖注入。我用 MS PP Unity 和构造函数注入以及方法和属性注入做了类似的事情。然后您的 Car 类将注入某种 IMakeInfo ...示例:

[InjectionMethod]
public void Initialize([Dependency] IMakeInfo makeInfo)
{
  this.MakeInfo = makeInfo;
}
于 2009-06-22T08:33:52.867 回答
0

最后(考虑到我工作的限制)我实际上使用了上述许多主题的变体。

因为由于循环引用的发生,我不得不避免对我的数据访问层的任何引用,所以我最终对委托和“工厂”代码做了一些事情。将其放入我的原始场景中,我做了以下事情:

class Car 
{
    public void SetLookupProvider(ILookupProvider value) { _lookupProvider = value; }

    public IMakeInfo Make { get { return _lookupProvider.ResolveMake(MakeId); } }

    ....
}

interface ILookupProvider
{
    IMakeInfo ResolveMake(int id);
}

class LookupProvider
{
    public delegate IMakeInfo ResolveMakeDelegate(int id);

    public ResolveMakeDelegate ResolveMakeDel { set { _resolvemake = value; } }

    public IMakeInfo ResolveMake(int id){ return _resolvemake(id); }  
}

然后在我的工厂方法中......

ICar returnedObject = new Car(blah, foo, bar, etc);

ILookupProvider luprovider = new LookupProvider();
luprovider.ResolveMakeDel = DataAccessLayer.FunctToGetMakeInfo;

(Car)returnedObject.SetLookupProvider(luprovider).

现在我第一个承认这不是最漂亮的解决方案(如果我访问 3.0 编译器,我会使用扩展方法......)但它确实保持 Car 类松散耦合到 DataAccess 层(在我的情况阻止了循环引用地狱......)。Car 类不需要知道它是如何获得结果的,首先生成 Car 对象的工厂方法是唯一与数据访问层耦合的东西。

我还没有标记答案,我会让更多的人投票然后选择最高的 - 特别是因为我认为它们都是有效的答案(只是在这种情况下我不能完全使用任何一个) .

于 2009-06-23T12:41:44.170 回答
0

由于 Car 类具有返回 IMakeInfo 的 Make 属性,因此看起来它已经提供了信息。那么我是否正确地假设您的问题更多是如何为汽车提供返回值?

如果是这种情况,也许您想创建一个了解汽车和 ResolveMake的工厂方法。

于 2009-06-22T08:32:52.917 回答
0

按照你的类比,Car 显然需要知道 get_Make 被称为 IMakeInfo 是什么。我也会考虑使汽车的一个关键特征。所以我认为将 IMakeInfo 传递给 Car 构造函数(可能使用 IOC)是非常合理的。如果这是与您的真实代码的一个很好的类比(每个“汽车”都有一个内在的“IMakeInfo”),我会选择这个。

您也可以使用 Johan 所说的 setter,同样可以使用可选的 IOC。我更喜欢构造函数的原因是,似乎每个“汽车”都应该有一个“制造”。

于 2009-06-22T08:39:04.980 回答