Oop 接口的功能主要是用于使用函数而不知道类是如何构建的吗?

Oop 接口的功能主要是用于使用函数而不知道类是如何构建的吗?,oop,interface,Oop,Interface,因为我理解接口是契约,所以我将其解释为契约词,即必须具有接口中指定的内容(例如打开、关闭、读取、写入处理文件的接口) 但是我很难理解的是,为什么你需要一个接口来告诉你这个类必须能够做什么,自从你在接口规范中写了它,你就不知道了吗 我能看到的接口的唯一原因是在大型项目中,您希望能够在不真正了解类是如何构建的情况下使用类。通过了解接口需要什么,您将知道如何使用它 这让我想知道为什么我应该在项目中使用(或者如果我应该)接口,而我将是唯一一个从事这项工作的人。我很确定它还有很多我看不到的用途 我的大部分

因为我理解接口是契约,所以我将其解释为契约词,即必须具有接口中指定的内容(例如打开、关闭、读取、写入处理文件的接口)

但是我很难理解的是,为什么你需要一个接口来告诉你这个类必须能够做什么,自从你在接口规范中写了它,你就不知道了吗

我能看到的接口的唯一原因是在大型项目中,您希望能够在不真正了解类是如何构建的情况下使用类。通过了解接口需要什么,您将知道如何使用它

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


我的大部分假设和解释都来自于和

你是对的,接口指定了契约,但实现可能会有很大的不同

简单示例:Java中的列表。列表是一个接口。两种常见的实现是ArrayList和LinkedList。每个人的行为不同,但履行相同的合同。我的意思是,ArrayList具有O(1)(常量)访问权限,而LinkedList具有O(n)访问权限

如果你还不明白O(1)和O(n)是什么意思,我建议你看一下

即使在您自己的代码(即不是或不会成为公共API的代码)上也要这样做的原因是:

  • 促进单元测试:你可以模拟一个接口,而你不能(或者不容易)模拟一个类;及
  • 允许您稍后更改实现,而不影响调用代码
但是我很难理解的是,为什么你需要一个接口来告诉你这个类必须能够做什么,自从你在接口规范中写了它,你就不知道了吗


当您编写外部可用的代码时,它也很好。在这种情况下,代码编写器不是
界面的用户。如果您要向用户提供一个库,那么您可能希望只记录
接口
,并允许
根据上下文进行更改,或者在不更改
接口

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

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

public void fireAll() {
    p01.fire();
    p02.fire();
    r01.fire();
    mg01.fire();
}
这种情况很糟糕,因为如果你添加或删除枪,你必须在一些地方更改代码。或者更糟糕的是,假设您希望能够在运行时添加和删除枪:这将变得更加困难

让我们制作一个接口,上面的每种枪都将实现它,称之为火器。现在我们可以这样做了

private Firearm[] firearms;

public void fireAll() {
    for (int i = 0; i < firearms.length; ++i) {
        firearms[i].fire();
    }
}
私人火器[]火器;
公众假期{
对于(int i=0;i<0.length;++i){
火器[i].火();
}
}

这有助于更好地进行更改,不是吗?

如果您想重新访问旧代码,您会感谢自己构建了一些接口。没有什么比想要实现一种新的已经存在的东西更令人沮丧的了,结果却发现你不记得一个新的对象必须拥有什么


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

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

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

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

// Bad!
public void logOut() {
    userNameLabel.setText("Nobody is logged in");
    userProfileWindow.close();
}
这是不赞成的,因为您的
用户
类现在与GUI紧密耦合。最好让
用户
类更加愚蠢,不要做太多事情。与其关闭
userProfileWindow
本身,不如告诉
userProfileWindow
用户已经注销,让
userProfileWindow
做它想做的任何事情(它想自己关闭)

实现这一点的方法是创建一个通用的
UserListener
接口,其中包含一个方法
loggedOut
,该方法在用户注销时由
User
类调用。任何想知道用户何时登录和注销的人都将实现这个界面

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();
    }
}
公共类用户{
//我们将保留一份希望收到注销通知的人员列表。我们不知道
//他们是谁,我们不在乎。任何想要得到通知的人都会得到通知
//通知。
私有静态列表侦听器;
公共void addListener(UserListener listener){
添加(侦听器);
}
//这将被调用…实际上,用户类不知道是谁在调用
//这就是原因。它可能是一个主菜单对象,因为用户选择了注销
//选项,或15年内未看到鼠标移动的InactivityTimer对象
//分钟,谁知道呢?
公开作废注销(){
//做任何需要做的内部簿记工作。
currentUser=null;
//现在用户已注销,请让所有人都知道!
for(UserListener侦听器:侦听器){
listener.logge
interface ICrushable
{
  void MakeCrushingSound();
}
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);
}
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));
    }

}
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 });
template <typename T>
void fun(const T& anObjectOfAnyType)
{
    anyThing.anyFunction();
}