面向对象编程中"接口"的定义是什么

Dan*_*nos 101 oop interface definition

好吧,我的一个朋友在编程中"界面"意味着来回走动.

什么是"界面"的最佳描述.

对我来说,一个接口是一个类的蓝图,这是最好的定义吗?

Uri*_*Uri 161

接口是开发中过载和混淆的术语之一.

它实际上是一个抽象和封装的概念.对于给定的"框",它声明该框的"输入"和"输出".在软件世界中,这通常意味着可以在框中调用的操作(以及参数),在某些情况下,这些操作的返回类型.

它没有做的是它没有定义这些操作的语义是什么,尽管在声明附近(例如,通过注释)记录它们是常见的(并且非常好的实践),或者选择好的命名约定.然而,无法保证会遵循这些意图.

这是一个类比:当电视关闭时看看你的电视.它的界面是它有的按钮,各种插头和屏幕.它的语义和行为是它需要输入(例如,有线节目)并具有输出(在屏幕上显示,声音等).但是,当您查看未插入的电视时,您将预期的语义投射到界面中.如你所知,当你插上电视时,电视可能会爆炸.但是,根据它的"界面",你可以假设它不会制作任何咖啡,因为它没有吸水量.

在面向对象的编程中,接口通常定义具有该接口的类的实例可以响应的方法(或消息)集.

令人困惑的是,在某些语言中,如Java,有一个实际的接口,其语言特定的语义.例如,在Java中,它是一组方法声明,没有实现,但是接口也对应于类型并遵循各种类型规则.

在其他语言中,如C++,您没有接口.类本身定义了方法,但您可以将类的接口视为非私有方法的声明.由于C++编译的方式,你可以得到头文件,你可以在没有实际实现的情况下拥有类的"接口".您还可以使用具有纯虚函数的抽象类来模仿Java接口等.

接口绝对不是一个类的蓝图.根据一个定义,蓝图是"详细的行动计划".接口承诺一个动作!混淆的原因在于,在大多数语言中,如果您有一个定义一组方法的接口类型,实现它的类"重复"相同的方法(但提供定义),因此接口看起来像一个骨架或一个班级大纲.


Yeh*_*ira 155

考虑以下情况:

当一个僵尸突然攻击你时,你正处在一个空旷的大房间中间.

你没有武器.

幸运的是,一个活着的人正站在房间的门口.

"快!" 你对他大喊大叫."扔给我一些我可以打到僵尸的东西!"

现在考虑:
没有指定(你也不关心)究竟是什么你的朋友会选择折腾;
......但是没关系,只要:

  • 这是可以扔的东西(他不能折腾你的沙发)

  • 这是你可以抓住的东西(让我们希望他没有扔掉手里剑)

  • 这是你可以用来打击僵尸大脑的东西(这排除了枕头等)

无论你是拿棒球棒还是锤子都没关系 -
只要它能实现你的三个条件,你就会很好.

把它们加起来:

当你写一个界面时,你基本上会说:"我需要一些东西......"

  • 实际上,枕头仍然有效.你可以用它击中僵尸.猛击僵尸的大脑......这是一个性能问题,它永远不会成为界面的一部分. (10认同)

Eug*_*hov 34

接口是您应遵守或给予的合同,具体取决于您是实施者还是用户.

  • 真正.接口是"方法签名契约",这意味着它保证实现给定的方法.它不能保证它是否以任何给定的方式这样做. (3认同)

Dav*_*sta 16

我认为"蓝图"不是一个好用的词.蓝图告诉您如何构建某些东西.界面特别避免告诉您如何构建某些东西.

接口定义了如何与类交互,即它支持哪些方法.

  • +1.界面是蓝图的对立面. (3认同)
  • 我相信请求者问的是定义是什么,而不是定义不是什么。:) (2认同)

Ste*_*n C 7

对我来说,一个接口是一个类的蓝图,这是最好的定义吗?

不,蓝图通常包括内部.但是接口纯粹是关于类外部可见的内容......或者更准确地说,是实现接口的类系列.

接口由方法和常量值的签名组成,还包括实现接口的类和使用它的其他类之间的(通常是非正式的)"行为合同".


Ghi*_*rny 5

从技术上讲,我将接口描述为一组与对象交互的方式(方法、属性、访问器……词汇取决于您使用的语言)。如果一个对象支持/实现一个接口,那么你可以使用接口中指定的所有方式来与这个对象交互。

从语义上讲,接口还可以包含关于您可以做什么或不可以做什么的约定(例如,您可以调用方法的顺序)以及作为回报,您可以根据您的交互方式假设对象的状态远的。


ces*_*sor 5

在编程中,接口定义了对象将具有的行为,但它实际上不会指定行为.这是一份合同,可以保证某个班级可以做某事.

在这里考虑这段C#代码:

using System;

public interface IGenerate
{
    int Generate();
}

// Dependencies
public class KnownNumber : IGenerate
{
    public int Generate() 
    {
        return 5;
    }   
}

public class SecretNumber : IGenerate
{
    public int Generate()
    {
        return new Random().Next(0, 10);
    }
}

// What you care about
class Game
{
    public Game(IGenerate generator) 
    {
        Console.WriteLine(generator.Generate())
    }
}

new Game(new SecretNumber());
new Game(new KnownNumber());
Run Code Online (Sandbox Code Playgroud)

Game类需要一个秘密号码.为了测试它,您希望注入将用作密码的内容(此原则称为控制反转).

游戏类希望对实际创建随机数的内容"开放",因此它会在其构造函数中询问"任何具有Generate方法的东西".

首先,接口指定对象将提供什么操作.它只包含它的外观,但没有给出实际的实现.这只是该方法的签名.通常,在C#接口中加上前缀I.这些类现在实现了IGenerate接口.这意味着编译器将确保它们都有一个返回int并被调用的方法Generate.游戏现在被称为两个不同的对象,每个对象都实现了正确的界面.其他类在构建代码时会产生错误.

在这里,我注意到您使用的蓝图类比:

类通常被视为对象的蓝图.一个接口指定了一个类需要做的事情,所以有人可能会说它确实只是一个类的蓝图,但由于一个类不一定需要一个接口,我认为这个比喻是破坏的.将接口视为合同."签署"的类别将在法律上要求(由编制警察强制执行),以遵守合同中的条款和条件.这意味着它必须做,界面中指定的内容.

这完全归功于某些OO语言的静态类型特性,就像Java或C#的情况一样.另一方面,在Python中,使用了另一种机制:

import random

# Dependencies
class KnownNumber(object):
    def generate(self):
        return 5

class SecretNumber(object):
    def generate(self):
        return random.randint(0,10)

# What you care about
class SecretGame(object):
    def __init__(self, number_generator):
        number = number_generator.generate()
        print number
Run Code Online (Sandbox Code Playgroud)

这里,没有类实现接口.Python并不关心这一点,因为SecretGame类只会尝试调用传入的任何对象.如果对象有一个generate()方法,一切都很好.如果没有:KAPUTT!这个错误不会在编译时看到,而是在运行时看到,所以可能在您的程序已经部署并运行时.C#会在你接近之前通知你.

使用这种机制的原因,天真地说,因为在OO语言中,自然功能不是一等公民.如您所见,KnownNumberSecretNumber包含JUST生成数字的函数.一个人根本不需要这些课程.因此,在Python中,人们可以将它们扔掉并自己选择函数:

# OO Approach
SecretGame(SecretNumber())
SecretGame(KnownNumber())

# Functional Approach

# Dependencies
class SecretGame(object):
    def __init__(self, generate):
        number =  generate()
        print number

SecretGame(lambda: random.randint(0,10))
SecretGame(lambda: 5)
Run Code Online (Sandbox Code Playgroud)

lambda只是一个函数,在你去的时候被宣布为"在行".委托在C#中是一样的:

class Game
{
    public Game(Func<int> generate) 
    {
        Console.WriteLine(generate())
    }
}    

new Game(() => 5);
new Game(() => new Random().Next(0, 10));
Run Code Online (Sandbox Code Playgroud)

后面的例子在Java中是不可能的,因为Java不能像其他两个(Python和C#)那样摇摆不定.在那里,接口是你在av中以这种方式表达行为的唯一方式.