Reputation: 3969
For the purposes of loose coupling and testing I am now replacing concrete references with interfaces and abstract classes, however I'm having trouble getting my head around the following scenario:
Say I have two concrete business layer objects whose only purpose is to call Data Access Logic methods and perform logic on the results before passing back to the controller (ASP.NET MVC 4), called FordCar
and CitroenCar
. They both inherit from a Car
abstract class, which inherits from ICar
interface:
public interface ICar
{
ICarDAL DAL;
bool StartEngine();
bool StopEngine();
Driver ChangeDriver(Driver d);
}
public abstract class Car : ICar
{
private ICarDAL DAL;
public virtual Car(ICarDAL DALInstance)
{
this.DAL = DALInstance;
}
public virtual bool StartEngine()
{
return this.DAL.UpdateEngine(true);
}
public virtual bool StopEngine()
{
return this.DAL.UpdateEngine(false);
}
public virtual Driver ChangeDriver(Driver d)
{
return this.DAL.UpdateDriver(d);
}
}
Because the DAL contains logic that is appropriate for all cars, I implement an interface and abstract class for this too:
public interface ICarDAL<T>
{
T EFContext;
bool UpdateEngine(bool b);
Driver UpdateDriver(Driver d);
}
public abstract class CarDAL<T> : ICarDAL<T>
{
private T EFContext;
public virtual bool UpdateEngine(bool b)
{
try
{
using(T db = new T())
{
// Perform DB update
// return true
}
}
catch(Exception e)
{
// Handle and return false
}
}
// and so on..
}
Now say the FordCar
has the ability to turn on windscreen heating, which the CitroenCar
does not have. This is where I lose sight, in order to be consistent I expect I'd have to implement an additional small interfaces and abstract classes for just FordCar
but how can I maintain using the abstract CarDAL
class - as it holds mostly common functionality - yet call TurnOnScreenHeating()
when it is not defined there? This requires a car type specific DAL classes, which defeats the object of my goal.
I suppose my question is: given lots of domain objects with mostly shared functionality how do I accommodate for the odd unique functionality when attempting loose coupling and dependency injection?
For in my controller I would hope to do this:
public class FordCarController : Controller
{
private Car BLLMethods;
public FordCarController()
{
// Init concrete type
this.BLLMethods = new FordCar();
}
public ActionResult DoHeating()
{
this.BLLMethods.TurnOnScreenHeating();
return View();
}
}
Apologies for the convoluted scenario and poor title.
Upvotes: 1
Views: 258
Reputation: 156624
I have a few observations. I'm hoping one or two of them will apply to the specific situation you're running into:
CitroenCar
and a FordCar
that inherit from Car
, you could just have a Car
with a Make
property to tell you which kind of car it is.IHaveWindscreenHeater
).ICar
class implement a bool CanHeatWindscreen{get;}
property, as well as a TurnOnScreenHeating()
method. This latter method could either do nothing or throw an exception in cars that don't have heating.FordController
tells me that you can no longer loosely couple this: You're declaring it to do stuff pertaining to Ford cars, so even if you manage to decouple it from the FordCar
class in code, you're still conceptually tightly coupled. This may be even more dangerous than having tight coupling in your code. Following observation #1 above, you may want to just use a single CarController
class that handles all your Car
actions.Upvotes: 4