接口允许您创建定义实现它的类的方法的代码。但是,您不能向这些方法添加任何代码。
抽象类使您可以做同样的事情,并向方法中添加代码。
现在,如果您可以使用抽象类实现相同的目标,那么为什么我们甚至需要接口的概念?
有人告诉我,它与从C ++到Java的OO理论有关,这是PHP的OO东西所基于的。这个概念在Java中有用但在PHP中没有用吗?这只是一种避免在抽象类中乱扔占位符的方法吗?我想念什么吗?
接口允许您创建定义实现它的类的方法的代码。但是,您不能向这些方法添加任何代码。
抽象类使您可以做同样的事情,并向方法中添加代码。
现在,如果您可以使用抽象类实现相同的目标,那么为什么我们甚至需要接口的概念?
有人告诉我,它与从C ++到Java的OO理论有关,这是PHP的OO东西所基于的。这个概念在Java中有用但在PHP中没有用吗?这只是一种避免在抽象类中乱扔占位符的方法吗?我想念什么吗?
Answers:
接口的全部目的是使您能够灵活地使您的类被强制实现多个接口,但仍不允许多重继承。从多个类继承的问题很多,而且各种各样,其上的Wikipedia页面对其进行了很好的总结。
接口是一种折衷。多重继承的大多数问题都不适用于抽象基类,因此,当今大多数现代语言都禁用了多重继承,但调用了抽象基类接口,并允许一个类“实现”所需的任意多个。
该概念在面向对象编程中非常有用。对我来说,我认为接口是一种合同。只要我的班级和您的班级就此方法签名合同达成协议,我们就可以“接口”。至于抽象类,我认为它们更多是一些某些方法的基类,因此我需要填写细节。
如果已经有抽象类,为什么还需要一个接口? 防止多重继承(可能导致多个已知问题)。
这些问题之一:
“钻石问题”(有时被称为“致命的死亡钻石”)是当两个B类和C类从A继承而D类从B和C继承时产生的歧义。 B和C已被覆盖,而D没有覆盖它,那么D会继承该方法的哪个版本:B或C?
资料来源:https : //zh.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
为什么/何时使用界面?
一个例子......世界上所有的汽车都有相同的接口(方法)... AccelerationPedalIsOnTheRight()
,BrakePedalISOnTheLeft()
。想象每个汽车品牌将具有与另一个品牌不同的“方法”。宝马的刹车器位于右侧,本田的刹车器位于车轮左侧。人们每次购买不同品牌的汽车时,都必须学习这些“方法”的工作方式。这就是为什么在多个“位置”具有相同的界面是一个好主意的原因。
接口对您有什么作用(为什么有人甚至会使用一个接口)?接口可防止您犯“错误”(它向您保证实现特定接口的所有类都将具有接口中的方法)。
// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{
public function Create($personObject);
}
class MySqlPerson implements IPersonService
{
public function Create($personObject)
{
// Create a new person in MySql database.
}
}
class MongoPerson implements IPersonService
{
public function Create($personObject)
{
// Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
}
}
这样,该Create()
方法将始终以相同的方式使用。不管我们使用的是MySqlPerson
类还是MongoPerson
类。我们使用方法的方式保持不变(接口保持不变)。
例如,它将像这样使用(在我们的代码中的任何地方):
new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);
这样,这样的事情就不会发生:
new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);
记住一个接口并在各处使用同一接口要比使用多个不同接口容易得多。
这样,Create()
对于不同的类,方法的内部可以不同,而不会影响调用此方法的“外部”代码。所有外部代码必须知道该方法Create()
具有1个参数($personObject
),因为外部代码将使用/调用该方法。外部代码不在乎方法内部发生了什么;它只需要知道如何使用/调用它。
您也可以在没有接口的情况下执行此操作,但是如果您使用接口,则它“更安全”(因为它可以防止您出错)。接口向您保证该方法Create()
在实现该接口的所有类中将具有相同的签名(相同的类型和相同数量的参数)。这样,您可以确保实现该IPersonService
接口的ANY类具有该方法Create()
(在此示例中),并且仅需要1个参数($personObject
)即可被调用/使用。
实现接口的类必须实现接口执行/具有的所有方法。
我希望我不要重复太多。
对于我来说,使用接口和抽象类之间的区别更多地与代码组织有关,而不是由语言本身来实施。在为其他开发人员准备代码时,我会经常使用它们,以使它们保持在预期的设计模式之内。接口是一种“按合同设计”,即您的代码同意响应一组规定的API调用,这些API调用可能来自您没有经验的代码。
虽然从抽象类继承是“是”关系,但这并不总是您想要的,实现接口更多的是“类似行为”关系。在某些情况下,这种差异可能非常显着。
例如,假设您有一个抽象类Account,从中扩展了许多其他类(帐户类型等)。它具有一组仅适用于该类型组的特定方法。但是,这些帐户子类中的某些实现了Versionable,Listable或Editable,以便可以将它们扔入希望使用这些API的控制器中。控制器不在乎它是什么类型的对象
相比之下,我还可以创建一个不从Account扩展的对象,例如User抽象类,并且仍然实现Listable和Editable,但不能实现Versionable,这在这里没有意义。
这样,我说的是FooUser子类不是一个帐户,但是它的行为就像一个Editable对象。同样,BarAccount从Account扩展而来,但不是User子类,而是实现Editable,Listable和Versionable。
将所有这些可编辑,可列出和可版本控制的API添加到抽象类本身中,不仅会变得凌乱和丑陋,而且会复制Account和User中的通用接口,或者强迫我的User对象实现Versionable,可能只是抛出一个例外。
您将在PHP中使用接口:
$object instanceof MyInterface
Car类实现EngineInterface,BodyInterface,SteeringInterface {
Car
对象现在可以start()
是stop()
(EngineInterface)或goRight()
,goLeft()
(Steering interface)
和其他我现在无法想到的事情
第4个可能是您无法使用抽象类解决的最明显的用例。
从Java思考:
一个接口说:“这就是实现该特定接口的所有类的样子。” 因此,任何使用特定接口的代码都知道可以为该接口调用哪些方法,仅此而已。因此,该接口用于在类之间建立“协议”。
接口不是作为类可以扩展的基础,而是作为所需功能的映射而存在。
以下是使用不适合抽象类的接口的示例:
假设我有一个日历应用程序,该应用程序允许用户从外部源导入日历数据。我将编写类来处理每种类型的数据源(ical,rss,atom,json)的导入。这些类中的每一个都将实现一个通用接口,以确保它们都具有我的应用程序获取数据所需的通用公共方法。
<?php
interface ImportableFeed
{
public function getEvents();
}
然后,当用户添加新的提要时,我可以确定提要的类型,并使用针对该类型开发的类来导入数据。为为特定的提要导入数据而编写的每个类都将具有完全不同的代码,否则这些类之间可能只有很少的相似性,而事实是它们是实现应用程序允许使用它们的接口所必需的。如果我要使用抽象类,则可以很容易地忽略一个事实,即我没有重写getEvents()方法,该方法将在这种情况下破坏我的应用程序,而如果使用任何方法,使用接口都不会让我的应用程序运行接口中定义的内容在实现它的类中不存在。我的应用程序不必关心它用于从Feed中获取数据的类,
为了更进一步,当我返回日历应用程序以添加其他供稿类型时,该界面被证明非常有用。使用ImportableFeed接口意味着我可以继续添加更多的类,只需添加实现此接口的新类,即可导入不同的提要类型。这使我可以添加大量功能,而不必向核心应用程序添加不必要的批量,因为核心应用程序仅依赖于接口需要的可用公共方法,只要我的新Feed导入类实现ImportableFeed接口,我知道我可以将其放到适当的位置并继续前进。
这只是一个非常简单的开始。然后,我可以创建实现我的所有日历类都需要的另一个接口,该接口提供了该类处理的供稿类型所特有的更多功能。另一个很好的例子是验证提要类型等的方法。
这超出了问题的范围,但是由于我使用了上面的示例:如果以这种方式使用接口,则会带来一系列问题。我发现自己需要确保从实现以匹配接口的方法返回的输出,并且要实现这一点,我使用一个读取PHPDoc块的IDE,并将返回类型作为类型提示添加到接口的PHPDoc块中,然后转换为实现它的具体类。然后,使用从实现此接口的类输出数据的类的我的类至少将知道在此示例中期望返回一个数组:
<?php
interface ImportableFeed
{
/**
* @return array
*/
public function getEvents();
}
比较抽象类和接口的空间不大。接口只是简单的映射,实现时要求类具有一组公共接口。
接口不仅用于确保开发人员实现某些方法。这样做的想法是,因为保证这些类具有某些方法,所以即使您不知道类的实际类型,也可以使用这些方法。例:
interface Readable {
String read();
}
List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
System.out.println(reader.read());
在许多情况下,提供或不提供抽象的基类是没有意义的,因为实现方式千差万别,除了一些方法外,没有任何共同点。
动态类型的语言具有“鸭嘴式”的概念,在这种情况下,您不需要接口。您可以自由地假定该对象具有您正在对其调用的方法。这可以解决静态类型的语言中的问题,在这种类型中,对象具有某种方法(在我的示例中为read()),但没有实现该接口。
我认为,接口应该比非功能性抽象类更可取。如果仅实例化一个对象,我将不会感到惊讶,因为仅实例化了一个对象,而不是解析两个对象,将它们组合在一起(尽管我不确定,我对内部工作原理并不熟悉。 OOP PHP)。
的确,与Java相比,接口没有那么有用/没有意义。另一方面,PHP6将引入更多类型提示,包括用于返回值的类型提示。这应该为PHP接口增加一些价值。
tl; dr:接口定义了需要遵循的方法列表(请考虑API),而抽象类则提供了一些基本/通用功能,子类可以根据特定需求进行细化。
接口不会给您的代码带来任何性能上的提升或类似的提升,但是它们在使代码可维护方面可以走很长一段路。确实可以使用抽象类(甚至是非抽象类)来建立代码的接口,但是正确的接口(使用关键字定义的接口并且仅包含方法签名)很容易实现。整理并阅读。
话虽如此,在决定是否在类上使用接口时,我倾向于谨慎使用。有时我想要默认的方法实现,或者所有子类都通用的变量。
当然,关于多接口实现的观点也很合理。如果您具有实现多个接口的类,则可以在同一应用程序中将该类的对象用作不同类型。
但是,您的问题是关于PHP的事实,这使事情变得更加有趣。在PHP中,对接口的键入仍然不是十分必要,在这里,您几乎可以将任何内容馈送给任何方法,而不管其类型如何。您可以静态地键入方法参数,但是其中一些参数是坏的(我相信字符串会引起一些麻烦)。再加上您不能键入大多数其他引用这一事实,并且试图在PHP中强制进行静态键入(在这一点上)没有太大价值。因此,在这一点上,PHP中接口的价值远远不及更强类型的语言。它们具有可读性的优点,但几乎没有其他优点。多重实现甚至没有好处,因为您仍然必须声明方法并将它们的主体提供给实现者。
以下是PHP接口的要点
示例代码:
interface test{
public function A($i);
public function B($j = 20);
}
class xyz implements test{
public function A($a){
echo "CLASS A Value is ".$a;
}
public function B($b){
echo "CLASS B Value is ".$b;
}
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);
我们看到抽象类和接口是相似的,因为它们提供了必须在子类中实现的抽象方法。但是,它们仍然存在以下差异:
1.接口可以包含抽象方法和常量,但不能包含具体方法和变量。
2.界面中的所有方法必须在公开可见性范围内。
3.一个类可以实现多个接口,而只能从一个抽象类继承。
interface abstract class
the code - abstract methods - abstract methods
- constants - constants
- concrete methods
- concrete variables
access modifiers
- public - public
- protected
- private
etc.
number of parents The same class can implement
more than 1 interface The child class can
inherit only from 1 abstract class
希望这会帮助任何人理解!
我不了解其他语言,那里的接口是什么概念。但是对于PHP,我将尽力解释。请耐心等待,如果有帮助,请发表评论。
接口充当“合同”,指定一组子类的功能,但不指定其操作方式。
规则
接口不能实例化。
您不能在接口中实现任何方法,即它仅包含该方法的.signature,而不包含details(body)。
接口可以包含方法和/或常量,但不能包含属性。接口常量与类常量具有相同的限制。接口方法是隐式抽象的。
接口不得声明构造函数或析构函数,因为它们是类级别的实现细节。
界面中的所有方法必须具有公共可见性。
现在举个例子。假设我们有两个玩具:一个是狗,另一个是猫。
众所周知,狗吠和猫叫。这两种说话方法相同,但功能或实现方式不同。假设我们给用户一个带有语音按钮的遥控器。
当用户按下“说话”按钮时,玩具必须说话,无论是狗还是猫。
这是使用接口而不是抽象类的一个好例子,因为实现是不同的。为什么?记得
如果需要通过添加一些非抽象方法来支持子类,则应使用抽象类。否则,接口将是您的选择。