我有一个包含多个方法的类,其中一个是Save()方法。我希望有不同的Save实现:保存到DB,保存到文件等等。所以,说这是类:
MyClass
Add()
Remove()
Save()
添加和删除实现对所有人都是通用的。只有Save会有所不同。在这种情况下,使用Save作为抽象方法创建抽象类是否更合适?或者使用界面有什么好处?如果我在这里使用接口,我需要复制Add和Remove的实现以及我实现接口的所有类,对吧?在这里只有一个只有Save方法的ISave接口是没有意义的,因为我的所有实现类仍然需要定义Add和Remove?
试着更好地理解接口和抽象类的用法......
不确定编程语言是否有所作为,但我使用的是C#。
答案 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
返回Add
或true
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; }
}