66

我已经多次看到从一个类生成一个接口实例。为什么我们要这样使用接口?接口实例仅在派生类的帮助下创建,我们只能通过该实例访问这些接口成员。这如何带来优势?我很混乱。

interface IPrint
{
    void Print();
}

class Sample : IPrint
{
    public void Print()
    {
        Console.WriteLine("Print...");
    }

    public void Sample()
    {
        Console.WriteLine("Sample...");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IPrint print = new Sample();
        print.Print();
    }
}
4

4 回答 4

107

接口定义了一个类必须能够做某事。这意味着您知道正在处理的对象将执行您想要执行的操作。它让您有更大的自由度,是 OOP 的优势之一。这是一个很深的话题,但一个非常基本的例子是:

public interface IAnimal
{
    string Speak();
}

public class Dog : IAnimal
{
    public string Speak()
    {
        return "Woof, woof";
    }
} 

public class Cat : IAnimal
{
    public string Speak()
    {
        return "Meow";
    }
} 

public class Parrot : IAnimal
{
    public string Speak()
    {
        return "Sqwark!";
    }
} 

然后你可以使用任何你喜欢的动物!

class Program
{
    static void Main(string[] args)
    {
        // Writes Woof, Woof
        IAnimal animal = new Dog();
        Console.WriteLine(animal.Speak());        

        // Now writes Meow
        animal = new Cat();
        Console.WriteLine(animal.Speak());

        // Now writes Sqwark etc
        animal = new Parrot();
        Console.WriteLine(animal.Speak());
    }
}

这也允许你进入控制反转之类的事情,你可以像这样拿一个物品,你可以通过一只狗、猫或鹦鹉,这种方法总是有效的,不知道或不关心它是哪种动物:

public void ShoutLoud(IAnimal animal)
{
    MessageBox.Show("Shout " + animal.Speak());
}

这使得 ShoutLoud可以进行单元测试,因为您可以使用模拟对象而不是真实的动物。它基本上使您的代码灵活和动态,而不是僵化和紧密耦合。

另外,扩展马修的问题。在 C# 中,您只能从一个基类继承,但可以有多个接口。所以,你可以有:

public class Dog : IAnimal, IMammal, ICarnivor

这允许您拥有小型界面(推荐),然后允许您进行构建,从而最大限度地控制项目可以/必须做什么。

于 2013-05-30T09:34:07.247 回答
10

以这种方式使用接口使您能够创建使用接口标准模板的方法。所以在这里你可能有很多类的打印机都继承自IPrinter

class SamsungPrinter : IPrinter
{
    // Stuff and interface members.
}

class SonyPrinter : IPrinter
{
    // Stuff and interface members.
}

interface IPrinter
{
    void Print();
}

因此,对于每种类型SamsungPrinter,SonyPrinter等,您可以使用类似的东西进行预处理

public static void PreProcessAndPrint(IPrinter printer)
{
    // Do pre-processing or something.
    printer.Print();
}

您从继承自IPrinter该类型并在方法参数中使用该类型知道,您始终可以安全地Print在传递的任何对象上使用该方法。

当然,使用接口还有许多其他用途。它们使用的一个例子是在设计模式中,特别是工厂和策略模式。可以在此处找到其中的描述和示例。

我希望这有帮助。

于 2013-05-30T09:31:22.410 回答
1

但这与例如使用带有虚拟方法的基类有何不同?

你们都假设一个程序员或一个程序编写接口和类,但这并不总是这样。

也许您有一个与动物一起使用的完整程序,并且您使用以下方法解决了这个问题:

public abstract class Animal { public abstract string Speak(); }

然后有一天你会从 nuget 下载一些很棒的 DLL,用于显示动物的图片。类库包含一个契约 - 接口 - 'IAnimal':

namespace AwesomeAnimalLibrary
{
public interface IAnimal
{
string AnimalName;
}
}

类库也可能包含:

namespace AwesomeAnimalLibrary
{
public class AnimalPhotos
{
[Byte] GetPhotos(IAnimal animal);
}
}

你现在能做什么?您的基础类 Animal 可以实现 AwesomeAnimalLibrary IAnimal 接口,仅此而已。

不要假设其他人会使用你的抽象基类,而是使用接口契约一起工作。

于 2013-06-01T10:47:58.647 回答
0

接口不能有实例,因为接口只实现属性或方法的签名。接口只是指向某个类的实例的指针:

interface IExample
{
   // method signature
   void MyMethod();
}
public class MyClass : IExample
{
   // method implementation
   public void MyMethod()
   {
      ConsoleWriteline("This is my method");
   }
}

// interface pointing to instance of class
IExample ie = new MyClass();
ie.MyMethod();
于 2017-04-14T09:52:02.907 回答