Dan*_*nos 101 oop interface definition
好吧,我的一个朋友在编程中"界面"意味着来回走动.
什么是"界面"的最佳描述.
对我来说,一个接口是一个类的蓝图,这是最好的定义吗?
Uri*_*Uri 161
接口是开发中过载和混淆的术语之一.
它实际上是一个抽象和封装的概念.对于给定的"框",它声明该框的"输入"和"输出".在软件世界中,这通常意味着可以在框中调用的操作(以及参数),在某些情况下,这些操作的返回类型.
它没有做的是它没有定义这些操作的语义是什么,尽管在声明附近(例如,通过注释)记录它们是常见的(并且非常好的实践),或者选择好的命名约定.然而,无法保证会遵循这些意图.
这是一个类比:当电视关闭时看看你的电视.它的界面是它有的按钮,各种插头和屏幕.它的语义和行为是它需要输入(例如,有线节目)并具有输出(在屏幕上显示,声音等).但是,当您查看未插入的电视时,您将预期的语义投射到界面中.如你所知,当你插上电视时,电视可能会爆炸.但是,根据它的"界面",你可以假设它不会制作任何咖啡,因为它没有吸水量.
在面向对象的编程中,接口通常定义具有该接口的类的实例可以响应的方法(或消息)集.
令人困惑的是,在某些语言中,如Java,有一个实际的接口,其语言特定的语义.例如,在Java中,它是一组方法声明,没有实现,但是接口也对应于类型并遵循各种类型规则.
在其他语言中,如C++,您没有接口.类本身定义了方法,但您可以将类的接口视为非私有方法的声明.由于C++编译的方式,你可以得到头文件,你可以在没有实际实现的情况下拥有类的"接口".您还可以使用具有纯虚函数的抽象类来模仿Java接口等.
接口绝对不是一个类的蓝图.根据一个定义,蓝图是"详细的行动计划".接口承诺一个动作!混淆的原因在于,在大多数语言中,如果您有一个定义一组方法的接口类型,实现它的类"重复"相同的方法(但提供定义),因此接口看起来像一个骨架或一个班级大纲.
Yeh*_*ira 155
考虑以下情况:
当一个僵尸突然攻击你时,你正处在一个空旷的大房间中间.
你没有武器.
幸运的是,一个活着的人正站在房间的门口.
"快!" 你对他大喊大叫."扔给我一些我可以打到僵尸的东西!"
现在考虑:
没有指定(你也不关心)究竟是什么你的朋友会选择折腾;
......但是没关系,只要:
这是可以扔的东西(他不能折腾你的沙发)
这是你可以抓住的东西(让我们希望他没有扔掉手里剑)
这是你可以用来打击僵尸大脑的东西(这排除了枕头等)
无论你是拿棒球棒还是锤子都没关系 -
只要它能实现你的三个条件,你就会很好.
把它们加起来:
当你写一个界面时,你基本上会说:"我需要一些东西......"
Dav*_*sta 16
我认为"蓝图"不是一个好用的词.蓝图告诉您如何构建某些东西.界面特别避免告诉您如何构建某些东西.
接口定义了如何与类交互,即它支持哪些方法.
对我来说,一个接口是一个类的蓝图,这是最好的定义吗?
不,蓝图通常包括内部.但是接口纯粹是关于类外部可见的内容......或者更准确地说,是实现接口的类系列.
接口由方法和常量值的签名组成,还包括实现接口的类和使用它的其他类之间的(通常是非正式的)"行为合同".
从技术上讲,我将接口描述为一组与对象交互的方式(方法、属性、访问器……词汇取决于您使用的语言)。如果一个对象支持/实现一个接口,那么你可以使用接口中指定的所有方式来与这个对象交互。
从语义上讲,接口还可以包含关于您可以做什么或不可以做什么的约定(例如,您可以调用方法的顺序)以及作为回报,您可以根据您的交互方式假设对象的状态远的。
在编程中,接口定义了对象将具有的行为,但它实际上不会指定行为.这是一份合同,可以保证某个班级可以做某事.
在这里考虑这段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语言中,自然功能不是一等公民.如您所见,KnownNumber并SecretNumber包含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中以这种方式表达行为的唯一方式.