【问题标题】:Can we use Abstract class instead of interface [duplicate]我们可以使用抽象类而不是接口吗[重复]
【发布时间】:2015-09-08 09:15:44
【问题描述】:

我已经开始了支持开发人员的职业生涯,但我梦想为软件开发人员找到一份工作。 我正在用 C# 学习 OOPS。经常困扰我的一件事是接口和抽象类的使用。何时使用接口,何时使用抽象类。我在谷歌上搜索这个主题,但无论我浏览什么答案,我看到所有人都试图解释什么是抽象和接口,但我不是在他们的定义之后,而是我想看看他们在现实世界程序中的实际用法。在这里我想强调一个使用接口的代码,但我认为完整的东西也可以用抽象类来设计。

参见下面使用接口的存储库设计模式代码 如果我将存储库公开为接口

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() 以给出自己的实现。

现在的问题是抽象类是否可以解决我的目的,那么为什么在这种情况下我们需要接口。如果涉及多重继承,那么接口将是首选,否则我们可以使用抽象类完成工作。

寻找有价值的 cmets 和建议。谢谢

【问题讨论】:

  • CLR 本身就充满了例子。这是最真实的。

标签: c# oop interface abstract-class


【解决方案1】:

当你有

时,你会使用一个抽象类
  • 要共享的代码。
  • 方法中的默认行为,但希望您的类的用户能够覆盖它。

时你会使用接口
  • 没有共享代码。
  • 它需要应用于许多对象,没有通用的基类。
  • 使公共方法的定义更加清晰并提供文档。
  • 您希望源代码是私有的。

您通常会将抽象类(用于共享代码)与接口(用于文档)一起使用。

【讨论】:

  • 我看到每个人都试图直接或间接地说什么是接口和抽象类,但是在这里我发布一个主题并尝试知道如果我用抽象类设计我的存储库模式将来会出现什么样的问题而不是界面。因此,如果可能的话,请查看我的帖子并使用代码示例进行描述,以突出可能出现什么样的问题或范围将如何缩小等
【解决方案2】:

接口仅提供您未来类的“描述”,而当您需要一些“未完成的功能”时使用抽象类。因此,如果你想要一个类提供一些逻辑和一些未实现的功能 - 你应该使用抽象类,但如果所有功能都没有实现 - 请改用接口。

【讨论】:

    【解决方案3】:

    如果您的所有实现共享一个公共代码基础实现,您应该使用抽象类。这意味着,接口将保证所有类都有相同的成员,但每个类都必须有自己的实现。

    如果您有一个抽象类作为基类,所有继承类共享相同的实现,除非它们覆盖它,这在许多情况下是不需要的,通常您只需要以不同的方式实现一个满是成员的手。

    接口 - 保证相同的成员。

    抽象类 - 共享通用代码基础。

    我的question 上提到了一些关于它的好想法,也许这对你有帮助。

    【讨论】:

    • 我看到每个人都试图直接或间接地说什么是接口和抽象类,但是在这里我发布一个主题并尝试知道如果我用抽象类设计我的存储库模式将来会出现什么样的问题而不是界面。因此,如果可能的话,请查看我的帖子并使用代码示例进行描述,以突出可能出现什么样的问题或范围将如何缩小等。
    【解决方案4】:

    当您需要提供的不仅仅是抽象成员来实现,还需要一些具体成员时,您可以使用抽象类:

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

    抽象类和接口还有许多其他用例,但要涵盖它们需要撰写一本书而不是简单的答案。我仍然认为上述解释应该为您提供所需的提示,以了解有关该主题的更多信息。

    【讨论】:

      【解决方案5】:

      我可以在这里写抽象类而不是接口吗?

      从技术上讲,是的,你可以。实际上,您不应该这样做。

      在这种特殊情况下,存储库的实现可能会有所不同。如果实现不同,接口将以清晰的方式声明所需的行为。如果所有存储库的实现都相同,或者某些方法相同,则可以证明使用抽象类是合理的。因此允许您将其他重复的代码移动到一个共享位置。

      【讨论】:

      • 不太清楚你想说什么.......你能不能用示例代码解释一下你所说的内容,并尝试说明如果接口被替换,将来可能会出现什么样的问题带有关于此存储库设计模式的抽象类。请提供示例,帮助我可视化可能导致抽象类的问题。谢谢
      【解决方案6】:

      你的特殊情况我宁愿使用定制接口或抽象类。 IEnumerable<T> 可以满足你的所有需求,不要重新发明轮子:

        public class EmployeeRepositoryEF: IEnumerable<Employee> {
          ...
        }
      
        public class EmployeeRepositoryXML: IEnumerable<Employee> { 
          ...
        }
      

      只要你想要一个数组,你只需要ToArray():

       EmployeeRepositoryEF myRepo = ...
      
       Employee[] staff = myRepo.ToArray(); // <- just ask for array 
      

      【讨论】:

        猜你喜欢
        • 2011-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-28
        • 2010-09-20
        • 1970-01-01
        • 2011-06-02
        相关资源
        最近更新 更多