可以用抽象类代替接口吗?
本文关键字:接口 抽象类 | 更新日期: 2023-09-27 18:11:44
我已经开始了支持开发人员的职业生涯,但我有梦想得到一份S/W开发工作。我正在用c#学习oop。经常有一件事困扰着我,那就是接口和抽象类的使用。何时使用接口,何时使用抽象类。我在谷歌上搜索这个话题,但不管我浏览的答案是什么,我看到所有的人都试图解释什么是抽象和接口,但我不是在他们的定义之后,而是想看到他们在现实世界程序中的实际用法。这里我想强调一个使用接口的代码,但我认为完整的东西也可以用抽象类来设计。
见下面使用接口的存储库设计模式代码如果我将存储库公开为接口
public interface IEmployeeRepository
{
Employee[] GetAll();
}
那么优点是我可以有尽可能多的实现,就像下面
public class EmployeeRepositoryEF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying your EF DbContext
}
}
public class EmployeeRepositoryXML: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying an XML file
}
}
public class EmployeeRepositoryWCF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying some remote WCF service
}
}
见上面的代码,其中有一个合约方法GetAll()
谁会扩展接口,然后他们可以提供自己的实现。这是优点,但我的问题是我可以写抽象类而不是接口在这里吗?
假设我有一个抽象类
abstract class AbsEmployeeRepository
{
abstract public Employee[] GetAll();
}
现在我的所有其他存储库将扩展抽象类AbsEmployeeRepository
和重写函数GetAll()
给出自己的实现。
现在的问题是,如果抽象类可以解决我的目的,那么为什么我们需要接口在这种情况下。如果考虑多重继承,则首选接口,否则我们可以使用抽象类来完成工作。
寻找有价值的意见和建议。由于
当您有
时,您将使用抽象类- 共享代码
- 方法中的默认行为,但希望你的类的用户能够重写它。
当
时使用接口- 没有共享代码
- 它需要应用于许多对象,没有共同的基类。
- 使公共方法的定义更清晰并提供文档。
- 你希望源代码是私有的
通常你会使用一个抽象类(用于共享代码)和一个接口(用于文档)。
接口只提供你未来类的"描述",而抽象类在你需要一些"未完成的功能"时使用。因此,如果你想有一个类提供一些逻辑和一些未实现的函数-你应该使用抽象类,但如果所有的函数都没有实现-使用接口代替。
如果您的所有实现共享一个公共代码基础实现,则应该使用抽象类。这意味着,接口将保证所有的类都有相同的成员,但是每个类必须有自己的实现。
如果你有一个抽象类作为基类,所有继承类共享相同的实现,除非它们覆盖它,这在许多情况下是不需要的,通常你只需要实现不同的成员。
接口-保证成员相同。
抽象类-共享公共代码基础。
在我的问题中提到了一些关于它的好想法,也许这对你有所帮助。
当您不仅需要提供抽象成员来实现,还需要提供一些具体成员时,可以使用抽象类:
public abstract class A
{
protected abstract void DoSomeCheck();
public void DoStuff()
{
// You don't know how DoSomeCheck will be implemented but
// you know a derived class must implement it
DoSomeCheck();
}
}
或者,您可以使用接口来定义契约,这些契约必须由实现者完成,以确保它们可以与您的代码一起工作:
// This car accepts any engine that implements IEngine
public class Car
{
public IEngine Engine { get; set; }
}
public interface IEngine
{
void Start();
}
对于抽象类和接口还有许多其他的用例,但是要涵盖它们需要写一本书,而不是一个简单的答案。我仍然认为以上的解释应该给你必要的提示,以了解更多的主题
可以用抽象类代替接口吗?
技术上,是的,你可以。实际上,你不应该。
在这种特殊情况下,存储库的实现可能是不同的。如果实现不同,接口将以一种清晰的方式声明期望的行为。如果所有存储库的实现是相同的,或者某些方法是相同的,那么使用抽象类是合理的。因此,允许您将其他重复的代码移动到一个共享位置。
在您的特殊情况下我宁愿而不是使用定制的接口或抽象类。有IEnumerable<T>
,你想要什么就做什么,不要重新发明轮子:
public class EmployeeRepositoryEF: IEnumerable<Employee> {
...
}
public class EmployeeRepositoryXML: IEnumerable<Employee> {
...
}
当你想要一个数组所有你需要做的是ToArray()
:
EmployeeRepositoryEF myRepo = ...
Employee[] staff = myRepo.ToArray(); // <- just ask for array