为什么我们从Interface而不是Class创建对象实例?

时间:2013-05-30 09:20:33

标签: c# class interface derived-class

我已经多次看到从类生成的Interface实例。为什么以这种方式使用接口? Interface实例仅在派生类的帮助下创建,我们只能通过此实例访问此接口成员。这有什么优势?我很困惑..

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 个答案:

答案 0 :(得分:91)

接口定义一个类必须能够做某事。这意味着您知道正在处理的对象将执行您希望能够执行的操作。它允许您更大的自由和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

这允许您拥有小型接口(推荐),然后允许您进行构建,从而最大程度地控制项目可以/必须执行的操作。

答案 1 :(得分:8)

通过这种方式使用界面,您可以创建使用界面标准模板的方法。所以在这里你可能有许多类继承自IPrinter

的打印机
class SamsungPrinter : IPrinter
{
    // Stuff and interface members.
}

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

interface IPrinter
{
    void Print();
}

因此,对于每种类型SamsungPrinterSonyPrinter等,您可以使用类似

之类的内容进行预处理
public static void PreProcessAndPrint(IPrinter printer)
{
    // Do pre-processing or something.
    printer.Print();
}

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

当然,使用接口还有很多其他用途。它们的一个使用示例是设计模式,特别是工厂和战略模式。可以找到其中的示例和示例here

我希望这会有所帮助。

答案 2 :(得分: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接口,就是这样。

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

答案 3 :(得分: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();