【问题标题】:Maintain consistent loose coupling given complex inheritance在给定复杂继承的情况下保持一致的松散耦合
【发布时间】:2014-04-22 15:36:23
【问题描述】:

出于松耦合和测试的目的,我现在用接口和抽象类替换具体引用,但是我无法理解以下场景:

假设我有两个具体的业务层对象,其唯一目的是调用数据访问逻辑方法并对结果执行逻辑,然后再传回控制器 (ASP.NET MVC 4),分别称为 FordCarCitroenCar。它们都继承自 Car 抽象类,该抽象类继承自 ICar 接口:

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

因为 DAL 包含适用于所有汽车的逻辑,所以我也为此实现了一个接口和抽象类:

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

现在说FordCar 可以打开挡风玻璃加热,而CitroenCar 没有。这是我看不到的地方,为了保持一致,我希望我必须为 FordCar 实现一个额外的小接口和抽象类,但是我如何使用抽象 CarDAL 类来维护 - 因为它最常见功能 - 当它没有在那里定义时调用TurnOnScreenHeating()?这需要特定于汽车类型的 DAL 类,这违背了我的目标。

我想我的问题是:给定大量具有大部分共享功能的域对象,我在尝试松散耦合和依赖注入时如何适应奇怪的独特功能?

对于我的控制器,我希望这样做:

public class FordCarController : Controller
{
    private Car BLLMethods;

    public FordCarController()
    {
        // Init concrete type
        this.BLLMethods = new FordCar();
    }

    public ActionResult DoHeating()
    {
        this.BLLMethods.TurnOnScreenHeating();
        return View();
    }
}

为令人费解的场景和糟糕的标题道歉。

【问题讨论】:

  • 您的 CarDAL 是一个抽象类,这意味着无论如何,您都必须创建 SomeSpecificCarDAL 的具体类型。你不能只有抽象类,归根结底我们确实需要实例化一些东西:)
  • 没错,为简洁起见,我没有为FordCarCitroenCar 包含具体类,但明确的汽车类型会初始化适当类型的DAL。我编辑了控制器代码以使其更清晰。
  • 我不是指你的汽车课程,我指的是你的 DAL 课程。您目前只有一个名为 CarDal 的抽象类,它不能被实例化,您仍然需要创建 DAL 的具体类型。
  • 如果您正在编写特定于 Ford 对象的 FordController,我希望您使用 Ford 类而不是 Car 类。想想看。您正在为福特汽车做一些特定的事情,而不是通用类属性。
  • @HamidShahid 我明白了,但是测试与FordCar 相关的ICar 接口的其他实现呢?

标签: c# asp.net asp.net-mvc inheritance dependency-injection


【解决方案1】:

我有一些观察。我希望其中一两个适用于您遇到的具体情况:

  1. 通常倾向于组合优于继承。换句话说,与其让CitroenCarFordCar 继承自Car,不如让CarMake 属性告诉你它是哪种汽车。
  2. 不要将功能基于您对特定类型汽车的了解,而是尝试专注于功能检查。您可以采取几种不同的方法。例如:
    1. 使对象实现特定于功能的接口 (IHaveWindscreenHeater)。
    2. 使ICar 主类实现bool CanHeatWindscreen{get;} 属性以及TurnOnScreenHeating() 方法。后一种方法要么什么都不做,要么在没有暖气的汽车中抛出异常。
  3. 您将控制器称为 FordController 的事实告诉我,您不能再松散地耦合这一点:您声明它做与福特汽车有关的事情,所以即使您设法将它与 @ 分离987654331@ 代码中的类,您在概念上仍然是紧密耦合的。这可能比代码中的紧密耦合更危险。根据上面的观察 #1,您可能只想使用单个 CarController 类来处理您的所有 Car 操作。

【讨论】:

    猜你喜欢
    • 2012-07-31
    • 1970-01-01
    • 2017-11-09
    • 2019-02-02
    • 2017-06-05
    • 1970-01-01
    • 2020-10-26
    • 2011-02-22
    • 1970-01-01
    相关资源
    最近更新 更多