在我的开发学习中,我觉得我必须学习更多关于接口的知识。
我经常读到它们,但我似乎无法理解它们。
我读过这样的例子:动物基类,IAnimal接口的东西,如“Walk”,“Run”,“GetLegs”等-但我从来没有工作过,觉得“嘿,我应该在这里使用接口!”
我错过了什么?为什么这个概念对我来说这么难理解!我只是害怕这样一个事实,我可能从来没有意识到一个具体的需要-主要是由于一些缺失的理解他们!这让我觉得我作为一名开发人员缺少了一些东西!如果有人有过这样的经历,并取得了突破,我会很感激一些关于如何理解这个概念的建议。谢谢你!
I like Jimmy's answer a lot, but I feel I need to add something to it. The key to the whole thing is the "able" in IProcessable . It indicates a capability (or property, but meaning "intrinsic quality", not in the sense of C# properties) of the object that implements the interface. IAnimal is probably not a good example for an interface, but IWalkable might be a good interface to have if your system has many things that can walk. You might have classes derived from Animal such as Dog, Cow, Fish, Snake. The first two would probably implement IWalkable, the latter two don't walk, so they wouldn't. Now you ask "why not just have another superclass, WalkingAnimal, that Dog and Cow derive from?". The answer is when you have something completely outside the inheritance tree that also can walk, such as a robot. Robot would implement IWalkable, but probably wouldn't derive from Animal. If you want a list of things that can walk, you type it as IWalkable and you can put all walking animals plus robots in the list.
现在,将IWalkable替换为IPersistable这样更像软件的东西,这样的类比就更接近你在实际程序中看到的情况了。
与任何为系统增加灵活性的编程技术一样,接口也增加了一定程度的复杂性。它们通常都很好,而且你可以在任何地方使用它(你可以为你的所有类创建一个接口)——但是这样做,你会创建一个更复杂的系统,更难维护。
像往常一样,这里有一个权衡:灵活性胜过可维护性。哪个更重要?没有答案——这取决于项目本身。但是请记住,每个软件都需要维护……
所以我的建议是:在真正需要接口之前不要使用它们。(使用Visual Studio,你可以在2秒内从现有的类中提取一个接口——所以不要着急。)
话虽如此,你什么时候需要创建一个接口呢?
当我重构一个突然需要处理两个或多个类似类的方法时,我就会这样做。然后创建一个接口,将该接口分配给两个(或多个)类似的类,并更改方法参数类型(将类类型替换为接口类型)。
它是有效的:o)
一个例外:当我模拟对象时,接口更容易使用。我经常为此创建接口。
PS:当我写“接口”时,我的意思是:“任何基类的接口”,包括纯接口类。请注意,抽象类通常比纯接口更好,因为您可以向它们添加逻辑。
此致,Sylvain。
假设你想要模拟当你试图睡觉时可能发生的烦恼。
接口前的模型
class Mosquito {
void flyAroundYourHead(){}
}
class Neighbour{
void startScreaming(){}
}
class LampJustOutsideYourWindow(){
void shineJustThroughYourWindow() {}
}
正如你清楚地看到的,当你试图睡觉时,许多“事情”都可能令人讨厌。
使用没有接口的类
但是在使用这些类时,我们遇到了一个问题。他们毫无共同之处。您必须分别调用每个方法。
class TestAnnoyingThings{
void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
if(mosquito != null){
mosquito.flyAroundYourHead();
}
if(neighbour!= null){
neighbour.startScreaming();
}
if(lamp!= null){
lamp.shineJustThroughYourWindow();
}
}
}
带有接口的模型
为了克服这个问题,我们可以引入一个iterface
interface Annoying{
public void annoy();
}
并在类中实现它
class Mosquito implements Annoying {
void flyAroundYourHead(){}
void annoy(){
flyAroundYourHead();
}
}
class Neighbour implements Annoying{
void startScreaming(){}
void annoy(){
startScreaming();
}
}
class LampJustOutsideYourWindow implements Annoying{
void shineJustThroughYourWindow() {}
void annoy(){
shineJustThroughYourWindow();
}
}
接口使用
这将使这些类的使用更容易
class TestAnnoyingThings{
void testAnnoyingThinks(Annoying annoying){
annoying.annoy();
}
}
它解决了一个具体的问题:
你有a b c d四种不同类型。在你的代码中,你可以这样写:
a.Process();
b.Process();
c.Process();
d.Process();
为什么不让他们实现IProcessable呢
List<IProcessable> list;
foreach(IProcessable p in list)
p.Process();
当你添加50种类型的类,它们都做同样的事情时,这种伸缩性会更好。
另一个具体问题是:
你有没有看过System.Linq.Enumerable?它定义了大量的扩展方法,可以对实现IEnumerable的任何类型进行操作。因为任何实现IEnumerable的东西基本上都在说“我支持无序foreach类型模式中的迭代”,所以你可以为任何可枚举类型定义复杂的行为(Count、Max、Where、Select等)。