views:

150

answers:

5

I have a situation in which I am attempting to keep my model and implementation as loosely coupled as possible, however I am faced with a situation where the coupling could potentially get a lot closer than I want.

I have a selection of 'Model' classes, all implementing interfaces. Additionally I have 'Data Access' classes, which provide a number of functions, one of which is decoding integer lookup values into their full 'object' representation.

Within my model classes I want to provide access to these decoded values without requiring the model to know about the data access classes.

A simplified example is:

/// 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...
    }

}

How do I enable the Car class to provide the IMakeInfo object to any consuming classes without directly making it aware of the ResolveMake class? In the actual instance I am working with the Car class is not in the same namespace as the ResolveMake class and it contains no references to any instances of it.

Some of my options:

  • Implement a delegate in Car which can be supplied with an instance of the GetMakeInfo method.
  • Some kind of dependency injection
  • Closely couple Car to ResolveMake and be done with it.
  • Any other options?

Any suggestions welcome!

+1  A: 

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
      }
   }
}

elsewhere:

using MakeExts;

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

Edit: For using Extension Methods in .NET 2.0, you need something like:

Basically, a class containing:

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

and a "using System.Runtime.CompilerServices" scattered in relevant places.

Stobor
Ah unfortunately in this case I'm using .net 2.0 - I'll retag the question.
Ash
http://kohari.org/2008/04/04/extension-methods-in-net-20/
Stobor
A: 

Since the Car class has a property Make which returns IMakeInfo it looks like it already provides the information. So am I right in assuming that your problem is more how the car is provided with the value to return?

If this is the case perhaps you want to look at creating a factory method which knows about cars and ResolveMake.

Mark
+1  A: 

It sounds like Dependency Injection to me. I have done similar things with MS PP Unity and both contructor injection as well as method and property injection. Then your Car class would have some sort of injection of the IMakeInfo...example:

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

Going with your analogy, the Car obviously needs to know by the time get_Make is called what the IMakeInfo is. I would also consider the make a key characteristic of the car. So I think passing a IMakeInfo to the Car constructor (possibly using IOC) is very reasonable. If this is a good analogy to your real code (each "Car" has a single, intrinsic, "IMakeInfo"), I would go with this.

You could also use a setter like Johan said, again with optional IOC. The reason I would prefer a constructor is that it seems every "Car" should have a "Make".

Matthew Flaschen
A: 

In the end (given the constraints I was working within) I actually used a variation on a number of the themes above.

Because I had to avoid any references to my data access layer due to circular references occurring I ended up doing something with delegates and the 'factory' code. Fitting it into my original scenario I did the following:

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); }  
}

Then in my factory method...

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

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

(Car)returnedObject.SetLookupProvider(luprovider).

Now I'm the first to admit that this isn't the prettiest solution (I would have gone with Extension methods had I access to a 3.0 compiler..) but it does keep the Car class loosely coupled to the DataAccess layer (which in my situation prevented circular reference hell...). The Car class doesn't need to know how it is getting the result and the factory method which is producing the Car objects in the first place is the only thing which is coupled to the Data access layer.

I've not marked an answer yet, I'll let a few more people vote then go with the highest - particularly as I think they are all valid answers (its just that I couldn't use any one in entirety in this instance).

Ash