当我可以直接实现这些方法时,为什么我应该在C#中使用接口

Lea*_*ner 106 c# oop abstraction interface class

我知道这是一个非常基本的问题,但是一位采访者以非常戏法的方式问我,我很无奈:(

我只知道接口的材料或理论定义,并且在我工作的许多项目中也实现了它.但我真的不明白为什么以及如何有用.

我也不了解界面中的一件事.即,例如,我们使用

conn.Dispose();在最后一块.但我没有看到该类正在实现或继承IDisposableinterface(SqlConnection)类我的意思.我想知道如何调用方法名称.同样,我不了解Dispose方法是如何工作的,因为我们需要使用我们自己的实现为所有接口方法实现函数体.接口如何被接受或命名为合同?到目前为止,这些问题一直在我心中滚动,坦率地说,我从来没有看到任何能以我能理解的方式解释我的问题的好线程.

MSDN像往常一样看起来非常可怕,没有一行是明确的(伙计们,善意的理由是谁进入高级开发,我强烈认为任何代码或文章应该达到任何人看到它的想法,因此像许多人说的那样,MSDN是没用的).

采访者说:

他有5种方法,他很乐意直接在课堂上实现它,但如果你必须选择抽象类或接口,你选择哪一种,为什么?我确实回答了他在各种博客中读到的所有内容,说明抽象类和界面的优缺点,但他不相信,他试图理解"为什么界面"."为什么抽象类"一般,即使我只能实现相同的方法一次而不是改变它.

我看不到网络中的任何地方,我可以得到一篇文章,可以清楚地解释我的接口及其功能.我是众多程序员中的一员,他们仍然不了解接口(我知道我使用的理论和方法)但不满意我清楚地理解它.

Gui*_*tos 90

当您想要创建类似的东西时,接口非常好:

using System;

namespace MyInterfaceExample
{
    public interface IMyLogInterface
    {
        //I want to have a specific method that I'll use in MyLogClass
        void WriteLog();       
    }

    public class MyClass : IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyClass was Logged");
        }
    }

    public class MyOtherClass : IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyOtherClass was Logged");
            Console.Write("And I Logged it different, than MyClass");
        }
    }

    public class MyLogClass
    {
        //I created a WriteLog method where I can pass as a parameter any object that implements IMyLogInterface.
        public static void WriteLog(IMyLogInterface myLogObject)
        {
            myLogObject.WriteLog(); //So I can use WriteLog here.
        }
    }

    public class MyMainClass
    {
        public void DoSomething()
        {
            MyClass aClass = new MyClass();
            MyOtherClass otherClass = new MyOtherClass();

            MyLogClass.WriteLog(aClass);//MyClass can log, and have his own implementation
            MyLogClass.WriteLog(otherClass); //As MyOtherClass also have his own implementation on how to log.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的例子中,我可以是一个编写开发人员MyLogClass,而其他开发人员可以创建他们的类,当他们想要记录时,他们实现了接口IMyLogInterface.就像他们问我需要实现什么来使用WriteLog()方法一样MyLogClass.他们将在界面中找到答案.

  • 我的问题是,如果你实例化`MyClass`和`MyOtherClass`为什么你不能简单地调用`aClass.WriteLog()`为什么要添加额外的步骤.`WriteLog()`的实现对于每个类都会保持不同,但是你已经拥有了这个对象,为什么要将它传递给一个处理程序类呢? (14认同)
  • 嘿,这看起来像是一个非常好的成分让我明白,我真的很感激,非常感谢:) :) (3认同)
  • @ZachM.如果我是对的,答案意味着,他不会实例化类,但其他开发人员将实例化类并将其作为参数传递给`MyLogClass``WriteLog`方法.所以他的方法可以处理任何实现`IMyLogInterface`的对象.[here](https://softwareengineering.stackexchange.com/a/145481/164824)是另一篇有趣的帖子. (2认同)

use*_*290 49

我使用接口的一个原因是它增加了代码的灵活性.假设我们得到了一个方法,它将类类型Account的对象作为参数,例如:

public void DoSomething(Account account) {
  // Do awesome stuff here.
}
Run Code Online (Sandbox Code Playgroud)

这个问题是方法参数是固定的帐户实现.如果您永远不需要任何其他类型的帐户,这很好.以此示例为例,它使用帐户接口作为参数.

public void DoSomething(IAccount account) {
  // Do awesome stuff here.
}
Run Code Online (Sandbox Code Playgroud)

此解决方案未针对实现进行修复,这意味着我可以向其传递SuperSavingsAccount或ExclusiveAccount(均实现IAccount接口)并为每个实现的帐户获取不同的行为.


Sli*_*SFT 42

接口是实施者必须遵循的合同.抽象类允许合同和共享实现 - 接口不能拥有的东西.类可以实现和继承多个接口.类只能扩展单个抽象类.

为什么接口

  • 您没有默认或共享代码实现
  • 您想共享数据合同(Web服务,SOA)
  • 每个接口实现者都有不同的实现(IDbCommand具有SqlCommandOracleCommand以特定方式实现接口)
  • 您想要支持多重继承.

为何抽象

  • @Silver我读了你在博客中输入的大部分内容,但我试图理解.我已经完成了WCF服务,暴露了接口(但它只是一个没有上游或下游的独立应用程序).因此,虽然我设计和实现了很好的接口,但我无法理解它.我的问题是,实际上,你只是分享方法名称合同意味着什么?这个怎么样有用:(我知道它只是强制实施所有的方法,但是如何?在你的帖子上面的界面上,第二点说分享,意味着你能给出一个实际的实时例子吗? (2认同)

Bri*_*ana 24

在此输入图像描述

所以在这个例子中,PowerSocket对其他对象一无所知.这些对象都依赖于PowerSocket提供的Power,因此它们实现了IPowerPlug,这样他们就可以连接到它.

接口很有用,因为它们提供了对象可以用来协同工作的契约,而无需了解彼此之间的任何其他内容.


Gab*_*oia 20

总之一句话 - 因为多态性!

如果您"编程到接口而不是实现",那么您可以将共享相同接口(类型)的不同对象作为参数注入到方法中.这样,您的方法代码不会与另一个类的任何实现相结合,这意味着它始终可以使用相同接口的新创建的对象.(开/关原则)

  • 查看依赖注入,并明确阅读设计模式 - GOF 可重用面向对象软件元素.


dr.*_*row 6

我相信在问这个问题时已经流了很多血,许多人试图通过解释正常人无法理解的类似机器人的术语来解决这个问题。

所以首先。要了解为什么接口和为什么抽象,您需要了解它们的用途。我个人在申请 Factory Class 时学到了这两个。你在这个链接上找到了一个很好的教程

现在让我们根据我已经给出的链接进行挖掘。

您有可能会根据用户要求更改的Vehicle类(例如添加TruckTankAirplane等。鉴于我们有

public class clsBike:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Bike");
    }
    #endregion
}
Run Code Online (Sandbox Code Playgroud)

public class clsCar:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Car");
    }
    #endregion
}
Run Code Online (Sandbox Code Playgroud)

并且两者都有 Contract Ichoice ,只是说 My Class 应该有 Buy 方法

public interface IChoice
{
    string Buy();
}
Run Code Online (Sandbox Code Playgroud)

现在,您会看到,该接口仅强制执行该方法,Buy()但让继承的类决定在实现该方法时要执行的操作。这是接口的局限性,使用纯接口,您可能最终会重复一些我们可以使用 abstact 自动实现的任务。在我们的例子中,假设购买每辆车都有折扣。

public abstract class Choice
{
    public abstract string Discount { get; }
    public abstract string Type { get; }
    public string Buy()
    {
       return "You buy" + Type + " with " + Discount;
}
public class clsBike: Choice
{
    public abstract string Discount { get { return "10% Discount Off"; } }
    public abstract string Type { get { return "Bike"; } }
}

public class clsCar:Choice
{
    public abstract string Discount { get { return " $15K Less"; } }
    public abstract string Type { get { return "Car"; } }
}
Run Code Online (Sandbox Code Playgroud)

现在使用工厂类,您可以实现相同的目的,但是在使用抽象时,您让基类执行该Buy()方法。

总结:接口契约让继承类做实现,而抽象类契约可以初始化实现(可以被继承类覆盖)