我正在尝试理解界面。
根据我对接口的了解,它们与类一起使用,并允许将类附加到接口类? 我不太明白这个概念。何时以及为什么要使用此功能?我正在阅读一本书,将行为放入课堂,然后通过连接一个共同的对象可以有多种行为?
创建类似
的内容 Vehicle myObject = new Vehicle();
Interface1 something = myObject;
something.someFunc();
Interface Interface1 {
void someFunc();
}
答案 0 :(得分:6)
接口是一种行为契约。它说“如果你实施我,你必须做这些事情”。任何实现接口的类都必须满足该合同(即提供所有接口中指定的所有内容的具体实现),以便进行编译。
从实施中分离行为是重用的一个例子。
在C#中,类可以实现许多接口,但只能从一个类继承。由于C#不支持多重继承(幸运的是),接口是一种产生类似内容的方法。
答案 1 :(得分:2)
您可以将合约视为一个界面。实现接口的类型必须提供接口中定义的所有方法。此外,其他代码可以将您的类型的实例视为接口的实例,而不知道确切的类型。这对于插件体系结构非常有用,在运行时加载插件并且您实际上无法预先知道哪种类型实现了您的接口。使用接口,您只需定义接口IPlugin并查找实现它的类型。
答案 2 :(得分:1)
接口是一种保证特定行为存在的方法。
详细说明上面的例子
something.someFunc();
您在代码中需要的是,无论传递给您的对象是什么,都应该实现someFunc()
方法。
在这种情况下,您传递的是Vehicle
。
现在,假设此代码位于方法内,而不是
void function ThisMethodCallsSomeFunc (Interface1 myObject)
{
myobject.someFunc();
}
现在,在这个方法中,我可以传递一个myObject of Vehicle(只要Vehicle实现Interface1)。但是,另外,假设我有另一个类“RavenousBugBlatter
”并且也实现了Interface1
,我可以将该对象传递给此ThisMethodCallsSomeFunc
并调出其someFunc
同样。
这有助于阐明接口在这种情况下的帮助吗?
答案 3 :(得分:1)
interface IFlyable
{
void Fly();
}
class Bird : IFlyable
{
public void Fly() { }
}
class Plane : IFlyable
{
public void Fly() { }
}
List<IFlyable> things = GetBirdInstancesAndPlaneInstancesMixed();
foreach(IFlyable item in things)
{
item.Fly();
}
Bird和Plane除了Object
之外没有共同的基类,但你可以看到我们可以在我们的程序中使用相同的接口来组合它们,因为它们具有相同的“功能”:Fly。
答案 4 :(得分:1)
我非常喜欢在Ninject文档中解释事物的方式,因此我将使用他们的示例。您可以随时阅读完整文档:https://github.com/ninject/ninject/wiki/_pages
假设你有一个像这样的剑类:
class Sword
{
public void Hit(string target)
{
Console.WriteLine("Chopped {0} clean in half", target);
}
}
剑可以击中某些东西。现在假设你有一个Samurai课程。这个Samurai类使用剑来攻击。
class Samurai
{
private Sword _sword;
public Samurai()
{
_sword = new Sword();
}
public void Attack(string target)
{
_sword.Hit(target);
}
}
这一切都很好,很好,就像这样:
class Program
{
public static void Main()
{
Samurai warrior = new Samurai();
warrior.Attack("the evildoers");
}
}
你现在有一个紧密耦合的Samurai类到Sword类。什么时候你想拥有武士军队?有些人使用剑,有些人使用BowAndArrow,有些人使用手里剑。每次添加新武器时都必须修改Samurai类。因为这就是剑,弓箭和手里剑。它们都是武士可用来击中的武器。
这是界面发挥作用的地方。让我们使用一个接口抽象出使用武器攻击的功能:
interface IWeapon
{
void Hit(string target);
}
class Sword : IWeapon
{
public void Hit(string target)
{
Console.WriteLine("Chopped {0} clean in half", target);
}
}
class BowAndArrow : IWeapon
{
public void Hit(string target)
{
Console.WriteLine("Shot {0} right in the chest!", target);
}
}
class Shuriken : IWeapon
{
public void Hit(string target)
{
Console.WriteLine("Pierced {0}'s armor", target);
}
}
我们现在拥有的是IWeapon接口和实现该接口的三个类。界面就像合同一样。它说“如果你实现我,你必须提供Hit方法。那些方法应该接受一个字符串参数,不应该返回任何东西”。
我们的武士会改变什么?它现在可以使用IWeapon接口,而不是与类Sword耦合,而不是:
class Samurai
{
private IWeapon _weapon;
public Samurai(IWeapon weapon)
{
_weapon = weapon;
}
public void Attack(string target)
{
_weapon.Hit(target);
}
}
现在Samurai班使用了IWeapon。因为实现IWeapon接口的每个类都同意提供Hit方法的合同,所以Samurai类不需要知道或关心它所使用的武器。它只知道它有一个武器,它可以命中是。
像这样:
class Program
{
public static void Main()
{
Samurai warrior1 = new Samurai(new Sword());
Samurai warrior2 = new Samurai(new Shuriken());
Samurai warrior3 = new Samurai(new BowAndArrow());
warrior1.Attack("the evildoers");
warrior2.Attack("the big guy in front");
warrior3.Attack("the scared guy running away");
}
}
我希望这是有道理的。
答案 5 :(得分:0)
将接口视为您的类应包含的定义,定义此框架然后将其应用于类,然后该类可以从接口定义这些函数。
MyClass : IMyInterface
当您可能有类似的对象实现相同的功能但其中的代码不同时,这对多态功能很有用。
答案 6 :(得分:0)
让我们举一个非常简单的例子,你需要一个接口:
假设您正在编写一个库来在屏幕上绘制对象。 为此,您可能有许多可以绘制的对象,例如:
class Cube {
void draw(//Draw a cube);
}
现在让我们说有些东西可以告诉那些物体画出自己。如果只有一些立方体,那很简单:“所有立方体:在屏幕上画出自己”
但是现在你想拥有不同类型的对象!这是界面发挥作用的地方:
interface DrawableObject {
void draw();
}
和
class Cube:DrawableObject {
void draw(//Draw the Cube);
}
class Triangle:DrawableObject {
void draw(//Draw the Cube);
}
class Circle:DrawableObject {
void draw(//Draw the Cube);
}
现在你可以这样做:“所有DrawableObjects:在屏幕上画出你自己”!因为Circle,Cube和Triangle都实现了DrawableObject,所以它们都必然会有“draw”方法。
答案 7 :(得分:0)
正如@Mitch Weat所说,Interface是一个强制实现方法签名代码的合同。
尝试查看类似掩码的接口,你可以通过这个掩码看一个类,而不用询问类是否能够做到这一点。如果类实现了接口,那么类将能够完成接口所描述的所有方法!
答案 8 :(得分:0)
接口定义了一组实现类必须具有的属性和方法。接口的主要用途是实现类可以作为它们实现的任何接口传递,这可以简化和面向未来的代码。
假设您想要创建一个方法,将一个集合中的所有数字相加。如果没有接口,您必须满足各种类型的集合:ArrayList,List,Queue,Stack,int [],LinkedList等等。 (还有很多很多)。但是,所有这些类都具有由其接口定义的常见行为,例如添加,删除和迭代。在这种情况下,您真正需要的是遍历集合的能力,因此您的方法可能如下所示:
public static int Sum(IEnumerable listOfInts)
{
int total = 0;
foreach (object obj in listOfInts)
{
if (obj is int)
total += (int)obj;
}
return total;
}
现在你可以传入任何对象,只要它实现IEnumerable,所有集合都会这样做。
int total = Sum(new int[] { 3, 51, -2, 4 });
或者:
ArrayList list = new ArrayList();
list.Add(4);
list.Add(52);
...
int total = Sum(list);
答案 9 :(得分:0)
如果您允许第三方开发人员为您的应用程序开发插件,那么界面在实际商业意义上有用的一种方式就是。
例如,让我们来看一个销售点应用程序。此应用程序将使用一定数量的外围设备 - 例如Symbol LS2208条形码扫描仪,Avery-Berkel Scales等。每个设备以不同方式操作和与软件通信,但您的POS软件只知道一些设置命令 - 例如条形码扫描器:ReadCode()IsCodeValid()Initialise()等。
下面的实现可能是任何东西,但你的POS软件只关心那些少数方法。所以你要定义一个名为IBarcodeScanner的接口,它声明了那些少数方法存根。
您的第三方开发人员希望添加对Symbol LS4015扫描仪的支持,例如,它以不同方式进行通信。他们为它编写自己的驱动程序,然后编写接口中定义的几个方法来公开所有功能。然后,您的POS软件可以调用这4种方法,并保证它可以正常工作 - 它不必关心开发人员完成的所有自定义,它只使用它知道的方法。在大规模开发中使生活变得更加容易。
答案 10 :(得分:0)
接口的关键特性是允许可能从不同对象层次结构派生的类被视为相同多态
例如
public interface IDoSomething
{
string DoIt();
}
public class ClassOne : TextBox, IDoSomething
{
public string DoIt()
{
return "OK from a textbox";
}
}
public class ClassTwo : Panel, IDoSomething
{
public string DoIt()
{
return "OK from a panel";
}
}
然后你可以多态地使用它们
List<IDoSomething> items = GetMyItems();
foreach (var item in items)
{
Console.WriteLine(item.DoIt());
}