接口的功能主要是在不知道如何构建类的情况下使用函数吗?

时间:2022-08-24 16:28:23

As I understand interfaces they are contracts, I interpret it as the contract word, ie must have what is specified in the interface (ex open, close, read, write for an interface handling files).

据我所知,接口是契约,我把它解释为契约词,即必须具有接口中指定的内容(ex打开,关闭,读取,写入接口处理文件)。

But what im having a hard time grasping is why you would need to have an interface that tells you what the class must be able to do at all, wouldnt you know that already since you wrote it in the interface specification?

但是我很难掌握的是为什么你需要有一个界面来告诉你类必须能够做什么,自从你在接口规范中编写它之后你就​​不知道了吗?

The only reason I can see for interfaces is in large projects where you want to be able to use a class without really knowing how it is built. By seeing what the interface requires will allow you to know how to use it.

我可以看到接口的唯一原因是在大型项目中,您希望能够在不知道如何构建类的情况下使用类。通过查看界面所需的内容,您可以了解如何使用它。

Which leads me to wonder why I should use (or if I should) interfaces in projects that I will be the only one working on. Im pretty sure there are more uses for it that im not seeing.

这让我想知道为什么我应该在项目中使用(或者如果我应该)接口,我将是唯一一个工作。我很确定它有更多的用途,我没有看到。

I took most of my assumptions and interpretations from this question and this vbforums post

我从这个问题和这个vbforums帖子中获取了我的大部分假设和解释

10 个解决方案

#1


Suppose you're writing a set of classes that implements guns. You might have a Pistol, a Rifle, and a MachineGun. Then, suppose you decide to use these classes in such a way that you'd like to perform the fire() action on each of these guns. You could do it this way:

假设您正在编写一组实现枪支的类。你可能有一把手枪,一把步枪和一把机枪。然后,假设您决定以这样的方式使用这些类,即您希望对每个枪执行fire()操作。你可以这样做:

private Pistol p01;
private Pistol p02;
private Rifle  r01;
private MachineGun mg01;

public void fireAll() {
    p01.fire();
    p02.fire();
    r01.fire();
    mg01.fire();
}

That kind of sucks, because you have to change code in a few places if you add or remove guns. Or even worse, suppose you want to be able to add and remove guns at runtime: it becomes even harder.

这种情况很糟糕,因为如果你添加或删除枪支,你必须在几个地方改变代码。或者更糟糕的是,假设您希望能够在运行时添加和删除枪支:它变得更加困难。

Let's make an interface that each of the above guns will implement, call it Firearm. Now we can do this.

让我们创建一个上面的每个枪将实现的接口,称之为Firearm。现在我们可以做到这一点。

private Firearm[] firearms;

public void fireAll() {
    for (int i = 0; i < firearms.length; ++i) {
        firearms[i].fire();
    }
}

That lends itself to changes a little bit better, wouldn't you say?

这有助于改变一点点,你不是吗?

#2


You're right in that interfaces specify the contract but the implementaiton can be vastly different.

你是正确的,接口指定合同,但实现可能会有很大的不同。

Simple example: lists in Java. List is an interface. Two common implementations are ArrayList and LinkedList. Each behaves different but honours the same contract. By that I mean that ArrayList has O(1) (constant) access whereas LinkedList has O(n) access.

简单示例:Java中的列表。 List是一个界面。两个常见的实现是ArrayList和LinkedList。每个行为都不同但尊重同一合同。我的意思是ArrayList具有O(1)(常量)访问,而LinkedList具有O(n)访问。

If you don't yet understand what O(1) and O(n) mean, I suggest you take a look at the Plain english explanation of Big O.

如果您还不了解O(1)和O(n)的含义,我建议您看一下Big O的简明英语解释。

The reason you do this even on your own code (ie something that isn't or won't be a public API) is to:

您甚至在自己的代码上执行此操作的原因(即,不是或将不是公共API的东西)是:

  • facilitate unit testing: you can mock up an interface whereas you can't (or can't easily) mock up a class; and
  • 便于单元测试:你可以模拟一个界面而你不能(或不能轻易)模拟一个类;和

  • to allow you to change the implementation later without affecting the calling code.
  • 允许您稍后更改实现而不影响调用代码。

#3


Interfaces are useful when you have two classes which need to work together but should be decoupled from each other as much as possible. A common example of this is when you use listeners to connect model and view together in the model-view-controller design pattern.

当你有两个需要一起工作的类但是应该尽可能地彼此解耦时,接口很有用。一个常见的例子是当您使用侦听器在模型 - 视图 - 控制器设计模式中将模型和视图连接在一起时。

For example, let's say you had a GUI application where users could log in and log out. When users log out you might, say, change your "Currently logged in as So-and-So" label and close all of the visible dialog windows.

例如,假设您有一个用户可以登录和注销的GUI应用程序。当用户注销时,您可能会更改“当前登录为某某”标签并关闭所有可见的对话框窗口。

Now you have a User class with a logOut method, and whenever logOut is called you want all of these things to happen. One way to do that is have the logOut method handle all of these tasks:

现在你有一个带有logOut方法的User类,每当调用logOut时你都希望发生所有这些事情。一种方法是让logOut方法处理所有这些任务:

// Bad!
public void logOut() {
    userNameLabel.setText("Nobody is logged in");
    userProfileWindow.close();
}

This is frowned upon because your User class is now tightly coupled to your GUI. It would be better to have the User class be dumber and not do so much. Instead of closing userProfileWindow itself it should just tell userProfileWindow that the user has logged out and let userProfileWindow do whatever it wants to do (it wants to close itself).

这是不赞成的,因为您的User类现在与您的GUI紧密耦合。最好让User类变得笨重而不是那么多。它应该只告诉userProfileWindow用户已经注销并让userProfileWindow做任何想做的事情(它想关闭自己),而不是关闭userProfileWindow本身。

The way to do this is by creating a generic UserListener interface with a method loggedOut that is called by the User class when the user logs out. Anybody who wants to know when the user logs in and logs out will then implement this interface.

这样做的方法是创建一个通用的UserListener接口,其中包含一个用户登出时由User类调用的方法loggedOut。任何想知道用户何时登录并注销的人都将实现此接口。

public class User {
    // We'll keep a list of people who want to be notified about logouts. We don't know
    // who they are, and we don't care. Anybody who wants to be notified will be
    // notified.
    private static List<UserListener> listeners;

    public void addListener(UserListener listener) {
        listeners.add(listener);
    }

    // This will get called by... actually, the User class doesn't know who's calling
    // this or why. It might be a MainMenu object because the user selected the Log Out
    // option, or an InactivityTimer object that hasn't seen the mouse move in 15
    // minutes, who knows?
    public void logOut() {
        // Do whatever internal bookkeeping needs to be done.
        currentUser = null;

        // Now that the user is logged out, let everyone know!
        for (UserListener listener: listeners) {
            listener.loggedOut(this);
        }
    }
}

// Anybody who cares about logouts will implement this interface and call
// User.addListener.
public interface UserListener {
    // This is an abstract method. Each different type of listener will implement this
    // method and do whatever it is they need to do when the user logs out.
    void loggedOut(User user);
}

// Imagine this is a window that shows the user's name, password, e-mail address, etc.
// When the user logs out this window needs to take action, namely by closing itself so
// this information isn't viewable by other users. To get notified it implements the
// UserListener interface and registers itself with the User class. Now the User.logOut
// method will cause this window to close, even though the User.java source file has no
// mention whatsoever of UserProfileWindow.
public class UserProfileWindow implements UserListener {
    public UserProfileWindow() {
        // This is a good place to register ourselves as interested observers of logout
        // events.
        User.addListener(this);
    }

    // Here we provide our own implementation of the abstract loggedOut method.
    public void loggedOut(User user) {
        this.close();
    }
}

The order of operations will look like this:

操作顺序如下:

  1. The application starts and a user logs in. She opens her UserProfileWindow.
  2. 应用程序启动,用户登录。她打开她的UserProfileWindow。

  3. The UserProfileWindow adds itself as a UserListener.
  4. UserProfileWindow将自身添加为UserListener。

  5. The user goes idle and doesn't touch the keyboard or mouse for 15 minutes.
  6. 用户空闲,不会触摸键盘或鼠标15分钟。

  7. An imagined InactivityTimer class notices and calls User.logOut.
  8. 想象的InactivityTimer类会注意到并调用User.logOut。

  9. User.logOut updates the model, clearing the currentUser variable. Now if anybody asks, there's nobody logged in.
  10. User.logOut更新模型,清除currentUser变量。现在,如果有人问,没有人登录。

  11. User.logOut loops through its listener list, calling loggedOut() on each listener.
  12. User.logOut遍历其侦听器列表,在每个侦听器上调用loggedOut()。

  13. The UserProfileWindow's loggedOut() method is invoked, which closes the window.
  14. 调用UserProfileWindow的loggedOut()方法,关闭窗口。

This is great because this User class knows absolutely nothing about who needs to know about log out events. It doesn't know that the user name label needs to be updated, that the profile window needs to be closed, none of that. If later we decide more things need to be done when a user logs out, the User class does not need to be changed at all.

这很好,因为这个User类完全不知道谁需要了解注销事件。它不知道需要更新用户名标签,需要关闭配置文件窗口,这些都不是。如果稍后我们决定在用户​​注销时需要完成更多的事情,则根本不需要更改User类。

So, the listener pattern is one example of where interfaces are super useful. Interfaces are all about decoupling classes, removing ties and dependencies between classes that need to interact with each other but should not have strong ties in their code to each other.

因此,侦听器模式是接口超级有用的一个示例。接口都是关于解耦类,删除需要相互交互但不应该在代码中彼此之间存在紧密联系的类之间的联系和依赖关系。

#4


But what im having a hard time grasping is why you would need to have an interface that tells you what the class must be able to do at all, wouldnt you know that already since you wrote it in the interface specification?

但是我很难掌握的是为什么你需要有一个界面来告诉你类必须能够做什么,自从你在接口规范中编写它之后你就​​不知道了吗?

It is also good when you are writing externally available code. In this case the code writer is not the user of the Interface. If you are delivering a library to users, you may want to document only the Interface, and allow the Class to change based on context or to evolve over time without changing the Interface.

在编写外部可用代码时也很好。在这种情况下,代码编写器不是接口的用户。如果要向用户提供库,您可能只想记录接口,并允许类根据上下文进行更改,或者在不更改接口的情况下随时间演变。

#5


Let's say you have two classes Car and Gorilla. These two classes have nothing to do with each other. But, let's say you also have a class that can crush things. Instead of defining a method that takes a Car and crushes it and then having a separate method that takes a Gorilla and crushes it, you make an Interface called ICrushable ...

假设你有两个类Car and Gorilla。这两个类彼此无关。但是,让我们说你也有一个可以粉碎事物的课程。而不是定义一个方法,它采取一个Car并粉碎它然后有一个单独的方法,需要一个Gorilla并粉碎它,你创建一个名为ICrushable的接口...

interface ICrushable
{
  void MakeCrushingSound();
}

Now you can have your car and your Gorilla implement ICrushable and your Car implement ICrushable and your crusher can then operate on an ICrushable instead of a Car and a Gorilla ...

现在你可以让你的汽车和你的大猩猩实现ICrushable和你的汽车工具ICrushable和你的破碎机然后可以在ICrushable而不是汽车和大猩猩...

public class Crusher
{
  public void Crush(ICrushable target)
  {
    target.MakeCrushingSound();
  }
}

public class Car : ICrushable
{
    public void MakeCrushingSound()
    {
        Console.WriteLine("Crunch!");
    }
}

public class Gorilla : ICrushable
{
    public void MakeCrushingSound()
    {
        Console.WriteLine("Squish!!");
    }
}

static void Main(string[] args)
{
  ICrushable c = new Car();      // get the ICrushable-ness of a Car
  ICrushable g = new Gorilla();  // get the ICrushable-ness of a Gorilla

  Crusher.Crush(c);
  Crusher.Crush(g);
}

And Viola! You have a Crusher that can crush Cars and get "Crunch!" and can crush Gorillas and get "Squish!". Without having to go through the process of finding a type-relationship between Cars and Gorillas and with compile-time type checking (instead of a runtime switch statement).

而且中提琴!你有一个破碎机可以粉碎汽车并获得“紧缩!”并且可以粉碎大猩猩并获得“Squish!”。无需经历查找Cars和Gorillas之间的类型关系以及编译时类型检查(而不是运行时切换语句)的过程。

Now, consider something less silly ... an Class that can be compared (IComparable) for example. The class will define how you compare two things of it's type.

现在,考虑一些不那么愚蠢的东西......一个可以比较的类(例如IComparable)。该类将定义如何比较它的两种类型的东西。

Per comment: Okay, let's make it so we can sort an array of Gorillas. First, we add something to sort by, say Weight (please ignore the dubious business logic of sorting Gorillas by weight ... it's not relevant here). Then we implement ICompararble ...

评论:好的,让我们这样做,这样我们就可以对一系列大猩猩进行排序。首先,我们添加一些东西来排序,比如说重量(请忽略按权重排序大猩猩的可疑业务逻辑......这里不相关)。然后我们实施ICompararble ......

public class Gorilla : ICrushable, IComparable
{
    public int Weight
    {
        get;
        set;
    }

    public void MakeCrushingSound()
    {
        Console.WriteLine("Squish!!");
    }

    public int CompareTo(object obj)
    {
        if (!(obj is Gorilla))
        {
            throw (new ArgumentException());
        }

        var lhs = this;
        var rhs = obj as Gorilla;

        return (lhs.Weight.CompareTo(rhs.Weight));
    }

}

Notice we have "gotten around" the restriction of single inheritance that many languages have. We are allowed to implement as many interfaces as we like. Now, just by doing that, we can use functionality that was written more than 10 years ago on a class I just wrote today (Array.Sort, Array.BinarySearch). We can now write the following code ...

请注意,我们已经“解决了”许多语言所具有的单一继承的限制。我们被允许实现尽可能多的接口。现在,通过这样做,我们可以使用10年前写的功能,这个功能是我刚才写的一个类(Array.Sort,Array.BinarySearch)。我们现在可以编写以下代码......

var gorillas = new Gorilla[] { new Gorilla() { Weight = 900 },
                               new Gorilla() { Weight = 800 },
                               new Gorilla() { Weight = 850 }
};

Array.Sort(gorillas);
var res = Array.BinarySearch(gorillas, 
    new Gorilla() { Weight = 850 });

My Gorillas get sorted and binary search finds the matching Gorilla with the Weight of 850.

我的大猩猩得到排序,二元搜索找到匹配的大猩猩与权重850。

#6


If you ever want to revisit your old code, you will thank yourself for having built yourself some interfaces. Nothing is more frustrating than wanting to implementing a new type of something that exists, only to realize you do not remember what a new object had to have.

如果你想重新访问旧代码,你会感谢自己为自己构建了一些接口。没有什么比想要实现存在的新类型更令人沮丧,只是意识到你不记得新对象必须拥有什么。

In Java, you can implement multiple interfaces, which sort of simulates multiple inheritance (an object with multiple parent objects). You can only extend one superclass.

在Java中,您可以实现多个接口,这些接口模拟多重继承(具有多个父对象的对象)。您只能扩展一个超类。

#7


No one forces you to write interface and there is no language enforces that even. Its a best practice and idiom that a good programmer would follow. You are the only one to use your code, and ya, you can write what you like but what if you leave the project and someone else has to maintain and/or extend it? Or what if some other projects consider using your code? Or even what if after a while, you have to revisit your code for adding features or refactoring? You would create a nightmare for these sorts of things. It will be hard to understand what your object relationships and contracts established b/w them.

没有人强迫你写界面,甚至没有语言强制执行。这是一个优秀的程序员会遵循的最佳实践和习惯用语。你是唯一一个使用你的代码的人,你可以写下你喜欢的内容,但如果你离开项目而其他人必须维护和/或扩展它呢?或者,如果其他一些项目考虑使用您的代码呢?或者甚至在一段时间后,您还需要重新访问代码以添加功能或重构?你会为这些事情制造一场噩梦。很难理解你的对象关系和合同是什么建立的。

#8


Abstraction: Code written to use an interface is reusable an never needs to change. In the below case, the sub will work with System.Array, System.ArrayList, System.Collection.CollectionBase, List of T, because they all implement IList. An existing class can easily implement an interface even when the class inherits another class. You could even write your class to implement IList to us in the sub. Or another program could also implement the interface to use in the sub.

抽象:使用接口编写的代码是可重用的,永远不需要改变。在下面的例子中,sub将使用System.Array,System.ArrayList,System.Collection.CollectionBase,List of T,因为它们都实现了IList。即使类继承了另一个类,现有的类也可以轻松实现接口。你甚至可以编写你的类来在sub中为我们实现IList。或者另一个程序也可以实现在sub中使用的接口。

public sub DoSomething(byval value as IList) end sub

public sub DoSomething(byval value as IList)end sub

You can also use multiple interfaces in a class, so a class can be both a IList and IEnumerable, in most languages you can on inherit one class.

您还可以在类中使用多个接口,因此类可以是IList和IEnumerable,在大多数语言中,您可以继承一个类。

I would also look at how they are used in the various frameworks.

我还将看看它们如何在各种框架中使用。

#9


As I understand your question why do we need Interfaces ? right ? Well we don't need them :)

据我所知,为什么我们需要接口?对 ?好吧,我们不需要它们:)

In C++ for example, when you define a template... say a dummy function that looks like ::

例如,在C ++中,当您定义模板时...说一个看起来像::

template <typename T>
void fun(const T& anObjectOfAnyType)
{
    anyThing.anyFunction();
}

you can use this function anywhere with any type that has a function called anyFunction... the only thing that the compiler is going to do, is to replace T with the name of the type, and compile the new piece of code...

您可以在任何具有任何名为anyFunction的函数的类型的任何地方使用此函数...编译器将要做的唯一事情是将T替换为类型的名称,并编译新的代码...

This is very error prone in fact. The reason is that if we plug in a type which does not have a anyFunction then we are going to get an error, that error is different every time, every line that can not be translated by the compiler will issue an error for it. You get A LOT of errors for the ONLY MISSING THING! The new type does not have the required functions to work correctly with our fun for example.

事实上,这非常容易出错。原因是如果我们插入一个没有anyFunction的类型,那么我们将得到一个错误,每次错误都不同,编译器无法翻译的每一行都会发出错误。你只会错过很多错误!例如,新类型没有必要的功能来正常使用我们的乐趣。

Now interfaces solve this whole issue, how ? If the type has the required functions, then it is suitable, if not then the compiler will issue an error that the type is not suitable.

现在接口解决了这整个问题,怎么样?如果类型具有所需的函数,那么它是合适的,否则编译器将发出该类型不适合的错误。

The template example is just for clarification, and if you want to imaging what will happen if java is without interfaces, then the only thing you have to do is to check for the existence of every function manually in every class, where you assume that class implements a particular function. The dirty work is done by the compiler :)

模板示例仅用于说明,如果您想要成像如果java没有接口会发生什么,那么您唯一要做的就是在每个类中手动检查每个函数是否存在,您假设该类实现特定的功能。脏工作由编译器完成:)

Thanks,

#10


an interface reduces what the client is dependent on (http://en.wikipedia.org/wiki/Dependency_inversion_principle). it allows for multiple implementations and the ability to change implementations at run time.

界面减少了客户端所依赖的内容(http://en.wikipedia.org/wiki/Dependency_inversion_principle)。它允许多个实现,并能够在运行时更改实现。

#1


Suppose you're writing a set of classes that implements guns. You might have a Pistol, a Rifle, and a MachineGun. Then, suppose you decide to use these classes in such a way that you'd like to perform the fire() action on each of these guns. You could do it this way:

假设您正在编写一组实现枪支的类。你可能有一把手枪,一把步枪和一把机枪。然后,假设您决定以这样的方式使用这些类,即您希望对每个枪执行fire()操作。你可以这样做:

private Pistol p01;
private Pistol p02;
private Rifle  r01;
private MachineGun mg01;

public void fireAll() {
    p01.fire();
    p02.fire();
    r01.fire();
    mg01.fire();
}

That kind of sucks, because you have to change code in a few places if you add or remove guns. Or even worse, suppose you want to be able to add and remove guns at runtime: it becomes even harder.

这种情况很糟糕,因为如果你添加或删除枪支,你必须在几个地方改变代码。或者更糟糕的是,假设您希望能够在运行时添加和删除枪支:它变得更加困难。

Let's make an interface that each of the above guns will implement, call it Firearm. Now we can do this.

让我们创建一个上面的每个枪将实现的接口,称之为Firearm。现在我们可以做到这一点。

private Firearm[] firearms;

public void fireAll() {
    for (int i = 0; i < firearms.length; ++i) {
        firearms[i].fire();
    }
}

That lends itself to changes a little bit better, wouldn't you say?

这有助于改变一点点,你不是吗?

#2


You're right in that interfaces specify the contract but the implementaiton can be vastly different.

你是正确的,接口指定合同,但实现可能会有很大的不同。

Simple example: lists in Java. List is an interface. Two common implementations are ArrayList and LinkedList. Each behaves different but honours the same contract. By that I mean that ArrayList has O(1) (constant) access whereas LinkedList has O(n) access.

简单示例:Java中的列表。 List是一个界面。两个常见的实现是ArrayList和LinkedList。每个行为都不同但尊重同一合同。我的意思是ArrayList具有O(1)(常量)访问,而LinkedList具有O(n)访问。

If you don't yet understand what O(1) and O(n) mean, I suggest you take a look at the Plain english explanation of Big O.

如果您还不了解O(1)和O(n)的含义,我建议您看一下Big O的简明英语解释。

The reason you do this even on your own code (ie something that isn't or won't be a public API) is to:

您甚至在自己的代码上执行此操作的原因(即,不是或将不是公共API的东西)是:

  • facilitate unit testing: you can mock up an interface whereas you can't (or can't easily) mock up a class; and
  • 便于单元测试:你可以模拟一个界面而你不能(或不能轻易)模拟一个类;和

  • to allow you to change the implementation later without affecting the calling code.
  • 允许您稍后更改实现而不影响调用代码。

#3


Interfaces are useful when you have two classes which need to work together but should be decoupled from each other as much as possible. A common example of this is when you use listeners to connect model and view together in the model-view-controller design pattern.

当你有两个需要一起工作的类但是应该尽可能地彼此解耦时,接口很有用。一个常见的例子是当您使用侦听器在模型 - 视图 - 控制器设计模式中将模型和视图连接在一起时。

For example, let's say you had a GUI application where users could log in and log out. When users log out you might, say, change your "Currently logged in as So-and-So" label and close all of the visible dialog windows.

例如,假设您有一个用户可以登录和注销的GUI应用程序。当用户注销时,您可能会更改“当前登录为某某”标签并关闭所有可见的对话框窗口。

Now you have a User class with a logOut method, and whenever logOut is called you want all of these things to happen. One way to do that is have the logOut method handle all of these tasks:

现在你有一个带有logOut方法的User类,每当调用logOut时你都希望发生所有这些事情。一种方法是让logOut方法处理所有这些任务:

// Bad!
public void logOut() {
    userNameLabel.setText("Nobody is logged in");
    userProfileWindow.close();
}

This is frowned upon because your User class is now tightly coupled to your GUI. It would be better to have the User class be dumber and not do so much. Instead of closing userProfileWindow itself it should just tell userProfileWindow that the user has logged out and let userProfileWindow do whatever it wants to do (it wants to close itself).

这是不赞成的,因为您的User类现在与您的GUI紧密耦合。最好让User类变得笨重而不是那么多。它应该只告诉userProfileWindow用户已经注销并让userProfileWindow做任何想做的事情(它想关闭自己),而不是关闭userProfileWindow本身。

The way to do this is by creating a generic UserListener interface with a method loggedOut that is called by the User class when the user logs out. Anybody who wants to know when the user logs in and logs out will then implement this interface.

这样做的方法是创建一个通用的UserListener接口,其中包含一个用户登出时由User类调用的方法loggedOut。任何想知道用户何时登录并注销的人都将实现此接口。

public class User {
    // We'll keep a list of people who want to be notified about logouts. We don't know
    // who they are, and we don't care. Anybody who wants to be notified will be
    // notified.
    private static List<UserListener> listeners;

    public void addListener(UserListener listener) {
        listeners.add(listener);
    }

    // This will get called by... actually, the User class doesn't know who's calling
    // this or why. It might be a MainMenu object because the user selected the Log Out
    // option, or an InactivityTimer object that hasn't seen the mouse move in 15
    // minutes, who knows?
    public void logOut() {
        // Do whatever internal bookkeeping needs to be done.
        currentUser = null;

        // Now that the user is logged out, let everyone know!
        for (UserListener listener: listeners) {
            listener.loggedOut(this);
        }
    }
}

// Anybody who cares about logouts will implement this interface and call
// User.addListener.
public interface UserListener {
    // This is an abstract method. Each different type of listener will implement this
    // method and do whatever it is they need to do when the user logs out.
    void loggedOut(User user);
}

// Imagine this is a window that shows the user's name, password, e-mail address, etc.
// When the user logs out this window needs to take action, namely by closing itself so
// this information isn't viewable by other users. To get notified it implements the
// UserListener interface and registers itself with the User class. Now the User.logOut
// method will cause this window to close, even though the User.java source file has no
// mention whatsoever of UserProfileWindow.
public class UserProfileWindow implements UserListener {
    public UserProfileWindow() {
        // This is a good place to register ourselves as interested observers of logout
        // events.
        User.addListener(this);
    }

    // Here we provide our own implementation of the abstract loggedOut method.
    public void loggedOut(User user) {
        this.close();
    }
}

The order of operations will look like this:

操作顺序如下:

  1. The application starts and a user logs in. She opens her UserProfileWindow.
  2. 应用程序启动,用户登录。她打开她的UserProfileWindow。

  3. The UserProfileWindow adds itself as a UserListener.
  4. UserProfileWindow将自身添加为UserListener。

  5. The user goes idle and doesn't touch the keyboard or mouse for 15 minutes.
  6. 用户空闲,不会触摸键盘或鼠标15分钟。

  7. An imagined InactivityTimer class notices and calls User.logOut.
  8. 想象的InactivityTimer类会注意到并调用User.logOut。

  9. User.logOut updates the model, clearing the currentUser variable. Now if anybody asks, there's nobody logged in.
  10. User.logOut更新模型,清除currentUser变量。现在,如果有人问,没有人登录。

  11. User.logOut loops through its listener list, calling loggedOut() on each listener.
  12. User.logOut遍历其侦听器列表,在每个侦听器上调用loggedOut()。

  13. The UserProfileWindow's loggedOut() method is invoked, which closes the window.
  14. 调用UserProfileWindow的loggedOut()方法,关闭窗口。

This is great because this User class knows absolutely nothing about who needs to know about log out events. It doesn't know that the user name label needs to be updated, that the profile window needs to be closed, none of that. If later we decide more things need to be done when a user logs out, the User class does not need to be changed at all.

这很好,因为这个User类完全不知道谁需要了解注销事件。它不知道需要更新用户名标签,需要关闭配置文件窗口,这些都不是。如果稍后我们决定在用户​​注销时需要完成更多的事情,则根本不需要更改User类。

So, the listener pattern is one example of where interfaces are super useful. Interfaces are all about decoupling classes, removing ties and dependencies between classes that need to interact with each other but should not have strong ties in their code to each other.

因此,侦听器模式是接口超级有用的一个示例。接口都是关于解耦类,删除需要相互交互但不应该在代码中彼此之间存在紧密联系的类之间的联系和依赖关系。

#4


But what im having a hard time grasping is why you would need to have an interface that tells you what the class must be able to do at all, wouldnt you know that already since you wrote it in the interface specification?

但是我很难掌握的是为什么你需要有一个界面来告诉你类必须能够做什么,自从你在接口规范中编写它之后你就​​不知道了吗?

It is also good when you are writing externally available code. In this case the code writer is not the user of the Interface. If you are delivering a library to users, you may want to document only the Interface, and allow the Class to change based on context or to evolve over time without changing the Interface.

在编写外部可用代码时也很好。在这种情况下,代码编写器不是接口的用户。如果要向用户提供库,您可能只想记录接口,并允许类根据上下文进行更改,或者在不更改接口的情况下随时间演变。

#5


Let's say you have two classes Car and Gorilla. These two classes have nothing to do with each other. But, let's say you also have a class that can crush things. Instead of defining a method that takes a Car and crushes it and then having a separate method that takes a Gorilla and crushes it, you make an Interface called ICrushable ...

假设你有两个类Car and Gorilla。这两个类彼此无关。但是,让我们说你也有一个可以粉碎事物的课程。而不是定义一个方法,它采取一个Car并粉碎它然后有一个单独的方法,需要一个Gorilla并粉碎它,你创建一个名为ICrushable的接口...

interface ICrushable
{
  void MakeCrushingSound();
}

Now you can have your car and your Gorilla implement ICrushable and your Car implement ICrushable and your crusher can then operate on an ICrushable instead of a Car and a Gorilla ...

现在你可以让你的汽车和你的大猩猩实现ICrushable和你的汽车工具ICrushable和你的破碎机然后可以在ICrushable而不是汽车和大猩猩...

public class Crusher
{
  public void Crush(ICrushable target)
  {
    target.MakeCrushingSound();
  }
}

public class Car : ICrushable
{
    public void MakeCrushingSound()
    {
        Console.WriteLine("Crunch!");
    }
}

public class Gorilla : ICrushable
{
    public void MakeCrushingSound()
    {
        Console.WriteLine("Squish!!");
    }
}

static void Main(string[] args)
{
  ICrushable c = new Car();      // get the ICrushable-ness of a Car
  ICrushable g = new Gorilla();  // get the ICrushable-ness of a Gorilla

  Crusher.Crush(c);
  Crusher.Crush(g);
}

And Viola! You have a Crusher that can crush Cars and get "Crunch!" and can crush Gorillas and get "Squish!". Without having to go through the process of finding a type-relationship between Cars and Gorillas and with compile-time type checking (instead of a runtime switch statement).

而且中提琴!你有一个破碎机可以粉碎汽车并获得“紧缩!”并且可以粉碎大猩猩并获得“Squish!”。无需经历查找Cars和Gorillas之间的类型关系以及编译时类型检查(而不是运行时切换语句)的过程。

Now, consider something less silly ... an Class that can be compared (IComparable) for example. The class will define how you compare two things of it's type.

现在,考虑一些不那么愚蠢的东西......一个可以比较的类(例如IComparable)。该类将定义如何比较它的两种类型的东西。

Per comment: Okay, let's make it so we can sort an array of Gorillas. First, we add something to sort by, say Weight (please ignore the dubious business logic of sorting Gorillas by weight ... it's not relevant here). Then we implement ICompararble ...

评论:好的,让我们这样做,这样我们就可以对一系列大猩猩进行排序。首先,我们添加一些东西来排序,比如说重量(请忽略按权重排序大猩猩的可疑业务逻辑......这里不相关)。然后我们实施ICompararble ......

public class Gorilla : ICrushable, IComparable
{
    public int Weight
    {
        get;
        set;
    }

    public void MakeCrushingSound()
    {
        Console.WriteLine("Squish!!");
    }

    public int CompareTo(object obj)
    {
        if (!(obj is Gorilla))
        {
            throw (new ArgumentException());
        }

        var lhs = this;
        var rhs = obj as Gorilla;

        return (lhs.Weight.CompareTo(rhs.Weight));
    }

}

Notice we have "gotten around" the restriction of single inheritance that many languages have. We are allowed to implement as many interfaces as we like. Now, just by doing that, we can use functionality that was written more than 10 years ago on a class I just wrote today (Array.Sort, Array.BinarySearch). We can now write the following code ...

请注意,我们已经“解决了”许多语言所具有的单一继承的限制。我们被允许实现尽可能多的接口。现在,通过这样做,我们可以使用10年前写的功能,这个功能是我刚才写的一个类(Array.Sort,Array.BinarySearch)。我们现在可以编写以下代码......

var gorillas = new Gorilla[] { new Gorilla() { Weight = 900 },
                               new Gorilla() { Weight = 800 },
                               new Gorilla() { Weight = 850 }
};

Array.Sort(gorillas);
var res = Array.BinarySearch(gorillas, 
    new Gorilla() { Weight = 850 });

My Gorillas get sorted and binary search finds the matching Gorilla with the Weight of 850.

我的大猩猩得到排序,二元搜索找到匹配的大猩猩与权重850。

#6


If you ever want to revisit your old code, you will thank yourself for having built yourself some interfaces. Nothing is more frustrating than wanting to implementing a new type of something that exists, only to realize you do not remember what a new object had to have.

如果你想重新访问旧代码,你会感谢自己为自己构建了一些接口。没有什么比想要实现存在的新类型更令人沮丧,只是意识到你不记得新对象必须拥有什么。

In Java, you can implement multiple interfaces, which sort of simulates multiple inheritance (an object with multiple parent objects). You can only extend one superclass.

在Java中,您可以实现多个接口,这些接口模拟多重继承(具有多个父对象的对象)。您只能扩展一个超类。

#7


No one forces you to write interface and there is no language enforces that even. Its a best practice and idiom that a good programmer would follow. You are the only one to use your code, and ya, you can write what you like but what if you leave the project and someone else has to maintain and/or extend it? Or what if some other projects consider using your code? Or even what if after a while, you have to revisit your code for adding features or refactoring? You would create a nightmare for these sorts of things. It will be hard to understand what your object relationships and contracts established b/w them.

没有人强迫你写界面,甚至没有语言强制执行。这是一个优秀的程序员会遵循的最佳实践和习惯用语。你是唯一一个使用你的代码的人,你可以写下你喜欢的内容,但如果你离开项目而其他人必须维护和/或扩展它呢?或者,如果其他一些项目考虑使用您的代码呢?或者甚至在一段时间后,您还需要重新访问代码以添加功能或重构?你会为这些事情制造一场噩梦。很难理解你的对象关系和合同是什么建立的。

#8


Abstraction: Code written to use an interface is reusable an never needs to change. In the below case, the sub will work with System.Array, System.ArrayList, System.Collection.CollectionBase, List of T, because they all implement IList. An existing class can easily implement an interface even when the class inherits another class. You could even write your class to implement IList to us in the sub. Or another program could also implement the interface to use in the sub.

抽象:使用接口编写的代码是可重用的,永远不需要改变。在下面的例子中,sub将使用System.Array,System.ArrayList,System.Collection.CollectionBase,List of T,因为它们都实现了IList。即使类继承了另一个类,现有的类也可以轻松实现接口。你甚至可以编写你的类来在sub中为我们实现IList。或者另一个程序也可以实现在sub中使用的接口。

public sub DoSomething(byval value as IList) end sub

public sub DoSomething(byval value as IList)end sub

You can also use multiple interfaces in a class, so a class can be both a IList and IEnumerable, in most languages you can on inherit one class.

您还可以在类中使用多个接口,因此类可以是IList和IEnumerable,在大多数语言中,您可以继承一个类。

I would also look at how they are used in the various frameworks.

我还将看看它们如何在各种框架中使用。

#9


As I understand your question why do we need Interfaces ? right ? Well we don't need them :)

据我所知,为什么我们需要接口?对 ?好吧,我们不需要它们:)

In C++ for example, when you define a template... say a dummy function that looks like ::

例如,在C ++中,当您定义模板时...说一个看起来像::

template <typename T>
void fun(const T& anObjectOfAnyType)
{
    anyThing.anyFunction();
}

you can use this function anywhere with any type that has a function called anyFunction... the only thing that the compiler is going to do, is to replace T with the name of the type, and compile the new piece of code...

您可以在任何具有任何名为anyFunction的函数的类型的任何地方使用此函数...编译器将要做的唯一事情是将T替换为类型的名称,并编译新的代码...

This is very error prone in fact. The reason is that if we plug in a type which does not have a anyFunction then we are going to get an error, that error is different every time, every line that can not be translated by the compiler will issue an error for it. You get A LOT of errors for the ONLY MISSING THING! The new type does not have the required functions to work correctly with our fun for example.

事实上,这非常容易出错。原因是如果我们插入一个没有anyFunction的类型,那么我们将得到一个错误,每次错误都不同,编译器无法翻译的每一行都会发出错误。你只会错过很多错误!例如,新类型没有必要的功能来正常使用我们的乐趣。

Now interfaces solve this whole issue, how ? If the type has the required functions, then it is suitable, if not then the compiler will issue an error that the type is not suitable.

现在接口解决了这整个问题,怎么样?如果类型具有所需的函数,那么它是合适的,否则编译器将发出该类型不适合的错误。

The template example is just for clarification, and if you want to imaging what will happen if java is without interfaces, then the only thing you have to do is to check for the existence of every function manually in every class, where you assume that class implements a particular function. The dirty work is done by the compiler :)

模板示例仅用于说明,如果您想要成像如果java没有接口会发生什么,那么您唯一要做的就是在每个类中手动检查每个函数是否存在,您假设该类实现特定的功能。脏工作由编译器完成:)

Thanks,

#10


an interface reduces what the client is dependent on (http://en.wikipedia.org/wiki/Dependency_inversion_principle). it allows for multiple implementations and the ability to change implementations at run time.

界面减少了客户端所依赖的内容(http://en.wikipedia.org/wiki/Dependency_inversion_principle)。它允许多个实现,并能够在运行时更改实现。