我真的不明白接口存在的原因。据我所知,这是c#中不存在的多继承的一种工作(至少我是这么被告知的)。
我所看到的是,您预定义了一些成员和函数,然后必须在类中再次重新定义它们。从而使接口成为冗余。它只是感觉像句法……嗯,垃圾对我来说(请没有冒犯的意思。Junk是指无用的东西)。
在下面的例子中,我将创建一个名为Pizza的基类,而不是一个接口。
简单示例(取自不同的堆栈溢出贡献)
public interface IPizza
{
public void Order();
}
public class PepperoniPizza : IPizza
{
public void Order()
{
//Order Pepperoni pizza
}
}
public class HawaiiPizza : IPizza
{
public void Order()
{
//Order HawaiiPizza
}
}
没有人真正清楚地解释过接口是如何有用的,所以我打算尝试一下(并从Shamim的回答中窃取一点想法)。
让我们以披萨订购服务为例。您可以有多种类型的披萨,每个披萨的共同操作是在系统中准备订单。每个披萨都要准备,但每个披萨的准备方式不同。例如,当点菜时,系统可能需要验证餐厅是否有特定的食材,并将不需要做深盘披萨的食材放在一边。
当用代码写这个的时候,技术上你可以这样做
public class Pizza
{
public void Prepare(PizzaType tp)
{
switch (tp)
{
case PizzaType.StuffedCrust:
// prepare stuffed crust ingredients in system
break;
case PizzaType.DeepDish:
// prepare deep dish ingredients in system
break;
//.... etc.
}
}
}
然而,深盘披萨(在c#术语中)可能需要在Prepare()方法中设置与填充披萨皮不同的属性,因此最终会有许多可选属性,并且类不能很好地伸缩(如果添加新的披萨类型会怎样)。
解决这个问题的正确方法是使用接口。界面声明所有披萨都可以准备,但每个披萨可以准备不同。如果你有以下接口:
public interface IPizza
{
void Prepare();
}
public class StuffedCrustPizza : IPizza
{
public void Prepare()
{
// Set settings in system for stuffed crust preparations
}
}
public class DeepDishPizza : IPizza
{
public void Prepare()
{
// Set settings in system for deep dish preparations
}
}
现在,您的订单处理代码不需要确切地知道订购了什么类型的披萨来处理配料。它只有:
public PreparePizzas(IList<IPizza> pizzas)
{
foreach (IPizza pizza in pizzas)
pizza.Prepare();
}
尽管每种类型的披萨都是不同的,但这部分代码并不需要关心我们处理的是哪种类型的披萨,它只知道它正在为披萨调用,因此每次调用Prepare都会根据其类型自动正确地准备每个披萨,即使集合有多种类型的披萨。
考虑一下不控制或不拥有基类的情况。
以可视化控件为例,在。net for Winforms中,它们都继承自。net框架中完全定义的基类Control。
让我们假设您从事创建自定义控件的业务。你想要建立新的按钮,文本框,列表视图,网格,等等,你希望他们都有特定的功能独特的控件集。
例如,你可能想要一种通用的方法来处理主题,或者一种通用的方法来处理本地化。
在这种情况下,你不能“只创建一个基类”,因为如果你这样做,你必须重新实现所有与控件相关的东西。
相反,您将从按钮,TextBox, ListView, GridView等下降,并添加您的代码。
但这就产生了一个问题,你现在如何识别哪些控件是“你的”,你如何构建一些代码来表明“对于窗体上所有属于我的控件,将主题设置为X”。
输入接口。
接口是一种查看对象、确定对象是否遵守某种约定的方法。
您可以创建“YourButton”,从Button向下延伸,并添加对所需的所有接口的支持。
这将允许您编写如下代码:
foreach (Control ctrl in Controls)
{
if (ctrl is IMyThemableControl)
((IMyThemableControl)ctrl).SetTheme(newTheme);
}
如果没有接口,这是不可能的,相反,你必须写这样的代码:
foreach (Control ctrl in Controls)
{
if (ctrl is MyThemableButton)
((MyThemableButton)ctrl).SetTheme(newTheme);
else if (ctrl is MyThemableTextBox)
((MyThemableTextBox)ctrl).SetTheme(newTheme);
else if (ctrl is MyThemableGridView)
((MyThemableGridView)ctrl).SetTheme(newTheme);
else ....
}