可以用抽象类代替接口吗?

本文关键字:接口 抽象类 | 更新日期: 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