这个问题的任何合适的模式?

时间:2009-06-22 08:23:45

标签: c# design-patterns .net-2.0 loose-coupling

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

我有一些'Model'类,所有实现接口。此外,我还有“数据访问”类,它提供了许多功能,其中一个功能是将整数查找值解码为完整的“对象”表示。

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

一个简单的例子是:

/// 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 to ResolveMake并完成它。
  • 还有其他选择吗?

欢迎任何建议!

5 个答案:

答案 0 :(得分:1)

Extension Methods

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”分散在相关的地方。

答案 1 :(得分:1)

这对我来说听起来像依赖注入。我已经用MS PP Unity做了类似的事情,同时也进行了构造函数注入以及方法和属性注入。 然后你的Car类会有一些注入IMakeInfo ......例如:

[InjectionMethod]
public void Initialize([Dependency] IMakeInfo makeInfo)
{
  this.MakeInfo = makeInfo;
}

答案 2 :(得分:0)

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

如果是这种情况,或许你想看一下创建一个了解汽车和ResolveMake的factory method

答案 3 :(得分:0)

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

你也可以使用像Johan这样的二传手,再次使用可选的IOC。我更喜欢构造函数的原因是它似乎每个“Car”应该有一个“Make”。

答案 4 :(得分: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对象的工厂方法是唯一耦合到数据访问层的方法。

我还没有给出答案,我会让更多的人投票然后选择最高的 - 特别是因为我认为他们都是有效的答案(只是我不能完全使用任何一个)这个例子)。