关于OOP:当我可以直接实现这些方法时,为什么我要在C#中使用接口?

Why I should go for Interfaces in C# when I can implement the methods directly

我知道这是一个非常基本的问题,但是一个面试官用非常巧妙的方式问我,我很无助:(

我只知道接口的材料或理论定义,并且在我从事的许多项目中实现了它。但我真的不明白这是为什么,如何有用。

我也不理解界面中的一件事。例如,我们使用

最终块中的conn.Dispose();。但我看不到类正在实现或继承我的意思是IDisposable接口(SqlConnection类)。我想知道如何调用方法名。同样,我不理解Dispose方法是如何工作的,因为我们需要用我们自己的实现来实现所有接口方法的函数体。那么接口是如何被接受或命名为契约的呢?这些问题一直萦绕在我的脑海中,直到现在,坦率地说,我从来没有看到过能用我能理解的方式来解释我的问题的好线索。

像往常一样,msdn看起来非常可怕,没有一行是明确的(各位,请原谅谁进入了高水平的开发,我强烈认为任何代码或文章应该达到任何人看到它,因此像许多其他人说,msdn是不使用的)。

采访者说:

他有5个方法,他很乐意直接在类中实现它,但是如果您必须使用抽象类或接口,那么您选择哪一个,为什么?我确实回答了他我在各种博客上读到的所有关于抽象类和接口的优点和缺点的东西,但他不相信,他试图理解"为什么接口"一般。为什么抽象类"一般来说,即使我只能实现一次相同的方法,而不是Gona更改它。

我在网络中看不到哪里,我可以得到一篇文章来清楚地解释我关于接口及其功能的知识。我是许多程序员中的一员,他们仍然不知道接口(我知道理论和我使用的方法),但不满意我清楚地理解它。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 using System;

namespace MyInterfaceExample
{
    public interface IMyLogInterface
    {
        //I want to have a especific 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 parameter any object that implement 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.
        }
    }
}

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


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

1
2
3
  public void DoSomething(Account account) {
  // Do awesome stuff here.
}

问题在于,方法参数是固定的,朝向一个帐户的实现。如果你不需要任何其他类型的账户,这是可以的。以这个例子为例,它使用一个帐户接口作为参数。

1
2
3
public void DoSomething(IAccount account) {
  // Do awesome stuff here.
}

此解决方案不固定于实现,这意味着我可以向它传递一个supersavingsAccount或exclusiveaccount(两者都实现IAccount接口),并为每个实现的帐户获得不同的行为。


接口是执行者必须遵循的合同。抽象类合约加共享实现——接口不存在的东西。种类可以实现和隐藏多个接口。类别只能扩展一个单一的抽象类。

为什么界面

  • 你没有缺陷或共享代码的实现
  • 你想分享数据合同(Web Services,SOA)
  • 你对每个界面的实现都有不同的方式
  • 你想支持多重遗传。

为什么摘要

  • 你有缺陷或共享码的实现
  • 你想要最小化复制码
  • 你想要简单的支持


一句话-因为多态性!

如果您"编程到接口,而不是实现",则可以将共享同一接口(类型)的不同对象作为参数注入到方法中。这样,您的方法代码就不会与另一个类的任何实现耦合,这意味着它总是可以与同一接口的新创建对象一起工作。(开/关原理)

  • 研究依赖注入并明确阅读设计模式——GOF开发的可重用面向对象软件的元素。

enter image description here

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

接口是有用的,因为它们提供了对象可以用来在一起工作而不需要知道彼此的任何其他信息的契约。


没有鸭子类型,因为你知道一种方法是在一组混凝土级上实现的,所以你不能用同样的方式对待他们。实现一个界面允许您处理所有类别的实现,作为相同类型的事情,同时考虑到界面的定义。


作为@user2211290的真实示例,回答:

ArrayList都有接口IList。下面我们有一个string[]和一个List,使用ilist进行一些常见的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
string[] col1 = {"zero","one","two","three","four"};
List<string> col2 = new List<string>{"zero","one","two","three"};

static void CheckForDigit(IList collection, string digit)
    {
        Console.Write(collection.Contains(digit));
        Console.Write("----");
        Console.WriteLine(collection.ToString());
    }

static void Main()
{
    CheckForDigit(col1,"one");   //True----System.String[]
    CheckForDigit(col2,"one");   //True----System.Collections.Generic.List`1[System.String]



//Another test:

    CheckForDigit(col1,"four");   //True----System.String[]
    CheckForDigit(col2,"four");   //false----System.Collections.Generic.List`1[System.String]
}

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

所以首先。要了解为什么是接口和为什么是抽象的,您需要了解它们的用途。我在申请工厂课程的时候学到了这两个。你在这个链接上找到了一个很好的图图图里亚语

现在,让我们从我已经给出的链接入手。

您的车辆类别可能会根据用户的要求而改变(如添加卡车、坦克、飞机等),并且我们

1
2
3
4
5
6
7
8
9
public class clsBike:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Bike");
    }
    #endregion
}

1
2
3
4
5
6
7
8
9
public class clsCar:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Car");
    }
    #endregion
}

两人都有合同书,简单地说我的课应该有购买方法。

1
2
3
4
public interface IChoice
{
    string Buy();
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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"; } }
}

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

In Summary : Interface contracts let the inherit class do the implementation
while Abstract class Contracts may initialize the implementation (which can override by Inherit class)


抽象类和界面都是合同。

合同的主意是你具体的行为。如果你说你已经执行了合同

中间面抽象的选择是

抽象类的任何非抽象后代都将执行合同。

版本

执行界面的任何分类都将执行合同。

所以,当你想具体说明所有后代的一些行为时,你使用抽象的摘要,必须实现并保存自己的界面,但现在遇到的一切都必须是后代。


有一个界面,你可以跟踪:

创建与实现不同切割的隔离界面,使其具有更大的凝聚力。

(2)Allow for multiple methods with the same name between interfaces,because hey,you have no conflicting implementation,just a signature.

您可以在您独立的界面上进行版本和隐藏,保证一个合同。

你的代码可以在抽象比混凝土更大的范围内解读,允许智能依赖性注射,包括注射测试莫克等。

我敢肯定,有很多原因,它们只是一点。

一个抽象类允许你有一个部分混凝土基底从一个界面来工作,这不是同一个界面,而是有它自己的质量,比如用模板法创建部分实现的能力。


你只能从一个抽象课中继承。您可以从多个接口中嵌入。这决定了我在大多数案件中使用的是什么。

抽象类的优势在于,你可以有一个基础实现。然而,在易失性的情况下,一个缺陷的实现是无用的,因为基准类不知道如何预先清洁事物。Thus,an interface would be more applicable.


我不会把一个界面的定义写在一个抽象的类别上,因为我认为你非常了解这个理论,我承认你的固有原则,所以让我们成为一个实用的。

因为你知道界面没有任何代码,所以吹牛是简单的理解。

如果你需要初始化你的类别的属性,提供一个结构,或者你想提供一个抽象的类别的一部分,那么,对于一个不允许你这样做的界面,你将是一个很好的方法。

所以,在非常一般的情况下,当你需要向客户提供一个制造商或代码时,你应该选择抽象的类别到界面


接口允许类设计师为终端用户提供非常清晰的方法。它们也是多态性的一个整体部分。


抽象类是为相关实体装箱的,其中as接口可用于不相关实体。

例如,如果我有两个实体,比如说动物和人类,那么我将进入一个界面,在这个界面中,如果我必须详细地说老虎、狮子,并且想要与动物联系,那么我将选择动物抽象类。

如下所示

1
2
3
4
5
6
7
8
9
10
11
   Interface            
   ____|____
  |        |
Animal   Human



  Animal (Abstract class)
   __|___
  |      |
Tiger   Lion