为什么我们从接口而不是类创建对象实例

本文关键字:创建对象 实例 我们 接口 为什么 | 更新日期: 2023-09-27 18:16:16

我见过很多次从一个类生成一个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();
    }
}

为什么我们从接口而不是类创建对象实例

接口定义了一个类必须能够做一些事情。这意味着您知道正在处理的对象将执行您希望能够执行的操作。它允许您更大的自由度,并且是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 单元可测试,因为您可以使用模拟对象而不是真实的动物。它基本上使你的代码灵活和动态,而不是僵化和紧密耦合。

同时,对Matthew的问题进行扩展。在c#中,你只能继承一个基类,但是你可以有多个接口。你可以输入:

public class Dog : IAnimal, IMammal, ICarnivor

这允许你有小的接口(推荐),然后允许你建立最大限度地控制一个项目可以/必须做什么。

以这种方式使用接口使您能够创建使用接口标准模板的方法。这里可能有很多打印机类它们都继承自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方法。

当然,使用接口还有许多其他用途。使用它们的一个例子是设计模式,特别是工厂和策略模式。

但是,这与使用带有虚方法的基类有什么不同呢?

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

也许你已经完成了一个与动物有关的完整程序,并且你已经使用:

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接口,就是这样。

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

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

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