我应该在这种情况下使用接口或抽象类吗?

时间:2014-08-12 19:43:19

标签: c# oop interface abstract-class

我有一个包含多个方法的类,其中一个是Save()方法。我希望有不同的Save实现:保存到DB,保存到文件等等。所以,说这是类:

MyClass 
  Add()
  Remove()
  Save()

添加和删除实现对所有人都是通用的。只有Save会有所不同。在这种情况下,使用Save作为抽象方法创建抽象类是否更合适?或者使用界面有什么好处?如果我在这里使用接口,我需要复制Add和Remove的实现以及我实现接口的所有类,对吧?在这里只有一个只有Save方法的ISave接口是没有意义的,因为我的所有实现类仍然需要定义Add和Remove?

试着更好地理解接口和抽象类的用法......

不确定编程语言是否有所作为,但我使用的是C#。

4 个答案:

答案 0 :(得分:3)

查看策略设计模式:http://en.wikipedia.org/wiki/Strategy_pattern

您可以创建一个ISave接口,并为您需要使用的每个保存方法创建此接口的一个实现。 FileSave,DBSave等等

您可以将一个ISave参数添加到MyClass的构造函数中,然后根据您要使用的保存方法将正确的实现传递给您的类。

答案 1 :(得分:2)

在您的特定场景中,我建议您使用Abstract类。根据MSDN Recommendations for Abstract Classes vs. Interfaces,适用于您的方案的建议是:

  
      
  • 如果要在组件的所有实现中提供通用的实现功能,请使用抽象类。抽象类允许您部分实现您的类,而接口不包含任何成员的实现。
  •   

在Abstract类中,您可以为“添加”和“删除”方法提供功能,并让实现者需要使用abstract(或VB中的MustOverride)覆盖Save方法。

请参阅完整文章以获取更多信息。

答案 2 :(得分:1)

我建议两者兼顾。由于两个派生类之间存在许多共同的代码,因此继承层次结构是有意义的。但是,如果您为类提取接口并始终通过它访问它们,如果您发现需要一个具有不同添加,保存和删除方法的新类,它将为您留下未来的灵活性。

答案 3 :(得分:0)

使用两者总是好的。

首先,定义一个接口

public interface IMyInterface
{
    bool Add();
    bool Remove();
    bool Save();
}

然后定义一个抽象类

public abstract MyBaseClass : IMyInterface
{
    public bool Add() { ... }

    public bool Remove() { ... }

    public abstract bool Save();
}

并在实现MyBaseClass的那些类中实现Save变体。

现在,当您需要传递对象时,请在代码中的每个位置使用IMyInterface。

这使您还能够测试事物。 当“添加”和Remove命中数据库以从表中添加/删除内容时,测试变得困难。 然后,您需要设置测试数据库环境,将测试指向该测试,并且必须确保在运行测试时始终在干净的表上运行。 但是,如果您只想测试在Add返回Addtrue

时调用false函数行为不同的行为,该怎么办?
public class Foo
{
    public int AddRange(MyBaseClass my, int count)
    {
        int retval = 0;
        while (count > 0)
        {
            if (my.Add())
                ++retval;
            --count;
        }
        return retval;
    }
}

现在很难测试,因为Add绑定到MyBaseClass。它会攻击数据库以及在测试期间可能可靠的所有内容。但是,你可以使用界面。因此,请将AddRange的签名更改为

public int AddRange(IMyInterface my, int count);

并定义您的测试

[TestMethod]
void AddRangeReturns0ForFailedAdd()
{
    var foo = new Foo();
    Assert.AreEqual(0, foo.AddRange(new Fail(), 0));
    Assert.AreEqual(0, foo.AddRange(new Fail(), 1));
    Assert.AreEqual(0, foo.AddRange(new Fail(), 100));
}

class Fail : IMyInterface
{
     public bool Add() { return false; }

     public bool Remove() { return false; }

     public bool Save() { return false; }
}