接口和抽象类之间究竟有什么区别?
接口
接口是一种契约:编写接口的人说,"嘿,我接受这样看起来的东西",而使用接口的人说,"好吧,我编写的类是这样的"。
接口是一个空的shell。只有方法的签名,这意味着方法没有主体。接口不能做任何事情。这只是一种模式。
例如(伪代码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // I say all motor vehicles should look like this: interface MotorVehicle { void run(); int getFuel(); } // My team mate complies and writes vehicle looking that way class Car implements MotorVehicle { int fuel; void run() { print("Wrroooooooom"); } int getFuel() { return this.fuel; } } |
实现一个接口只消耗很少的CPU,因为它不是一个类,只是一堆名称,因此不需要进行任何昂贵的查找。当它很重要的时候,比如在嵌入式设备中,它是伟大的。
抽象类与接口不同,抽象类是类。它们使用起来更昂贵,因为当您从它们继承时需要进行查找。
抽象类看起来很像接口,但它们还有更多的功能:您可以为它们定义一个行为。这更像是一个人说,"这些类应该是这样的,它们有共同之处,所以请填空!"
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // I say all motor vehicles should look like this: abstract class MotorVehicle { int fuel; // They ALL have fuel, so lets implement this for everybody. int getFuel() { return this.fuel; } // That can be very different, force them to provide their // own implementation. abstract void run(); } // My teammate complies and writes vehicle looking that way class Car extends MotorVehicle { void run() { print("Wrroooooooom"); } } |
实现
虽然抽象类和接口应该是不同的概念,但是实现有时会使这种说法不正确。有时候,他们甚至不是你想的那样。
在Java中,这条规则得到了强有力的执行,而在PHP中,接口是抽象类,没有声明方法。
在Python中,抽象类更多的是一种编程技巧,您可以从ABC模块中获得,它实际上使用元类,因此也使用类。接口与这种语言中的duck类型更相关,它混合了约定和调用描述符的特殊方法(称为……method__方法)。
和编程一样,有理论、实践和另一种语言的实践:-)
抽象类和接口之间的关键技术区别是:
抽象类可以有常量、成员、方法存根(没有主体的方法)和定义的方法,而接口只能有常量和方法存根。
抽象类的方法和成员可以用任何可见性定义,而接口的所有方法都必须定义为
继承抽象类时,具体的子类必须定义抽象方法,而抽象类可以扩展另一个抽象类,而不必定义来自父类的抽象方法。
类似地,扩展另一个接口的接口不负责实现来自父接口的方法。这是因为接口不能定义任何实现。
子类只能扩展一个类(抽象的或具体的),而接口可以扩展或类可以实现多个其他接口。
子类可以定义具有相同或较少限制的可见性的抽象方法,而实现接口的类必须定义具有完全相同的可见性(公共)的方法。
接口只包含功能的定义/签名,如果我们有一些公共功能和公共签名,那么我们需要使用抽象类。通过使用抽象类,我们可以同时提供行为和功能。另一个继承抽象类的开发人员可以很容易地使用这个功能,因为他们只需要填补空白。
来自:
http://www.dotnetbull.com/2011/11/difference-between-abstract-class-and.html
http://www.dotnetbull.com/2011/11/what-is-abstract-class-in-c-net.htmlhttp://www.dotnetbull.com/2011/11/what-is-interface-in-c-net.html
可以在这里找到一个解释:http://www.developer.com/lang/php/article.php/3604111/ php -5- oop - interface - abstract - class -and-the- adapter - pattern.htm
An abstract class is a class that is
only partially implemented by the
programmer. It may contain one or more
abstract methods. An abstract method
is simply a function definition that
serves to tell the programmer that the
method must be implemented in a child
class.An interface is similar to an abstract
class; indeed interfaces occupy the
same namespace as classes and abstract
classes. For that reason, you cannot
define an interface with the same name
as a class. An interface is a fully
abstract class; none of its methods
are implemented and instead of a class
sub-classing from it, it is said to
implement that interface.
无论如何,我觉得这个接口的解释有点令人困惑。更常见的定义是:接口定义了实现类必须实现的契约。接口定义由公共成员的签名组成,没有任何实现代码。
一些重要的差异:
以表格形式:
正如来自javapaper的Joe所说:
1.Main difference is methods of a Java interface are implicitly abstract and cannot have implementations. A Java abstract class can
have instance methods that implements a default behavior.2.Variables declared in a Java interface is by default final. An abstract class may contain non-final variables.
3.Members of a Java interface are public by default. A Java abstract class can have the usual flavors of class members like private,
protected, etc..4.Java interface should be implemented using keyword"implements"; A Java abstract class should be extended using keyword"extends".
5.An interface can extend another Java interface only, an abstract class can extend another Java class and implement multiple Java
interfaces.6.A Java class can implement multiple interfaces but it can extend only one abstract class.
7.Interface is absolutely abstract and cannot be instantiated; A Java abstract class also cannot be instantiated, but can be invoked if a
main() exists.8.In comparison with java abstract classes, java interfaces are slow as it requires extra indirection.
我不想强调差异,这已经在许多答案中说过(关于接口&中变量的公共静态final修饰符;支持抽象类中的受保护的私有方法)
简单地说,我想说:
接口:通过多个不相关的对象实现契约
抽象类:在多个相关对象之间实现相同或不同的行为
从Oracle文档中
考虑使用抽象类,如果:
您希望在几个密切相关的类之间共享代码。您希望扩展抽象类的类具有许多公共方法或字段,或者需要访问修饰符而不是public(如protected和private)。您希望声明非静态或非final字段。考虑在以下情况下使用接口:
您期望不相关的类将实现您的接口。例如,许多不相关的对象可以实现抽象类与具体类建立"是"关系。接口为类提供"拥有"功能。
如果你正在寻找
Java 8通过提供
有关详细信息,请参阅此文档页面。
为了更好地理解代码示例,请查看这个SE问题。
我应该如何解释接口和抽象类之间的区别?
重点是:
抽象是面向对象的。它提供了一个"对象"应该具有和/或能够执行的函数的基本数据。它关注对象的基本特征:它拥有什么,它能做什么。因此,继承自同一个抽象类的对象具有相同的基本特征(泛化)。接口是面向功能的。它定义了一个对象应该具有的功能。不管它是什么对象,只要它能够执行接口中定义的这些功能,就可以了。它忽略了其他一切。一个对象/类可以包含几个(组)功能;因此,一个类可以实现多个接口。我正在建造一座300层的大楼
建筑的蓝图界面
例如,Servlet(我)高达200层的建筑——部分完成——摘要
部分实现,例如,通用和HTTP servlet建筑completed-concrete
完整的实现,例如,拥有servlet接口
我们对实现一无所知,只知道需求。我们可以找一个界面。默认情况下,每个方法都是公共的和抽象的它是一个100%纯抽象类如果我们声明public,我们就不能声明private和protected如果我们声明抽象,我们就不能声明final、static、synchronized、strictfp和native每个接口都有公共接口、静态接口和final接口序列化和瞬态是不适用的,因为我们不能为in接口创建实例非挥发性,因为它是最终的每个变量都是静态的在接口中声明变量时,需要在声明时初始化变量不允许实例和静态块摘要
部分实现它有一个抽象的方法。此外,它使用混凝土抽象类方法修饰符没有限制抽象类变量修饰符没有限制除了抽象,我们不能声明其他修饰符初始化变量没有限制摘自DurgaJobs网站
当您希望在继承层次结构中提供多态行为时,请使用抽象类。
当您想要完全不相关的类的多态行为时,请使用接口。
让我们再来看看这个问题:
首先要让你知道的是1/1和1*1的结果是一样的,但这并不意味着乘法和除法是一样的。很明显,他们的关系很好,但是要注意你们俩是不同的。
我将指出主要的区别,其余的已经解释过了:
抽象类对于建模类层次结构非常有用。任何需求的第一眼看上去,我们都部分清楚要构建什么,但是我们知道要构建什么。抽象类就是基类。
接口对于让其他层次结构或类知道我能够做什么很有用。当你说我有能力做某件事的时候,你必须有这种能力。接口将把它标记为强制类来实现相同的功能。
其实很简单。
您可以将接口看作一个类,它只允许有抽象方法,而不允许有其他任何东西。
因此接口只能"声明"而不能定义您希望类具有的行为。
抽象类允许您声明(使用抽象方法)和定义(使用完整方法实现)您希望该类具有的行为。
常规类只允许您定义而不是声明您希望类具有的行为/操作。
最后一件事,
在Java中,可以实现多个接口,但只能扩展一个(抽象类或类)…
这意味着定义行为的继承被限制为每个类只允许一个…也就是说,如果你想要一个类来封装从类a,B&C的行为,你需要做以下工作:类a扩展B,类C扩展a ..这是一种多继承的迂回方式……
另一方面,您可以简单地做:接口C实现A、B
因此,实际上Java只在"声明的行为"ie接口中支持多重继承,并且只支持带有定义行为的单继承。除非你照我说的那样做……
希望这能说得通。
接口与抽象类的比较是错误的。应该有另外两个比较:1)接口vs.类,2)抽象vs. final类。
接口和类
接口是两个对象之间的契约。我是邮递员,你是一个要送的包裹。我希望你知道你的送货地址。当有人给我一个包裹,它必须知道它的送货地址:
1 2 3 | interface Package { String address(); } |
类是一组遵守契约的对象。我是"盒子"集团的一员,我服从邮递员的合同。同时遵守其他合同:
1 2 3 4 5 6 7 8 9 10 | class Box implements Package, Property { @Override String address() { return"5th Street, New York, NY"; } @Override Human owner() { // this method is part of another contract } } |
文摘vs最终
抽象类是一组不完整的对象。他们不能使用,因为他们错过了一些部分。例如,我是一个抽象的gps感知框-我知道如何检查我在地图上的位置:
1 2 3 4 5 6 7 | abstract class GpsBox implements Package { @Override public abstract String address(); protected Coordinates whereAmI() { // connect to GPS and return my current position } } |
这个类,如果被另一个类继承/扩展,会非常有用。但是它本身是无用的,因为它没有对象。抽象类可以构建最终类的元素。
Final类是一组完整的对象,可以使用,但不能修改。他们知道如何工作和做什么。例如:I'm a Box that always go to the address during its construction:
1 2 3 4 5 6 7 8 9 10 | final class DirectBox implements Package { private final String to; public DirectBox(String addr) { this.to = addr; } @Override public String address() { return this.to; } } |
在大多数语言中,如Java或c++,可能只有一个类,既不抽象也不最终。这样的类可以继承,也可以实例化。不过,我认为这并不完全符合面向对象的范例。
同样,将接口与抽象类进行比较是不正确的。
简而言之,差异如下:
接口和抽象类的语法差异:
抽象类的方法和成员可以具有任何可见性。接口的所有方法都必须是公共的。//不再适用于Java 9抽象类的具体子类必须定义所有抽象方法。抽象子类可以有抽象方法。扩展另一个接口的接口不需要为从父接口继承的方法提供默认实现。子类只能扩展一个类。一个接口可以扩展多个接口。一个类可以实现多个接口。子类可以定义具有相同或较少限制的可见性的抽象方法,而实现接口的类必须将所有接口方法定义为公共的。抽象类可以有构造函数,但不能有接口。Java 9中的接口具有私有的静态方法。现在在接口:
唯一的区别是一个可以参与多重继承,而另一个不能。
接口的定义随着时间而变化。您是否认为接口仅仅具有方法声明并且仅仅是契约?那么静态最终变量和Java 8之后的默认定义呢?
接口被引入Java是因为多重继承的菱形问题,而这正是他们真正想做的。
接口是为了避免多重继承问题而创建的构造,可以有抽象方法、缺省定义和静态最终变量。
请参阅为什么Java允许接口中只包含契约的静态最终变量?
接口:左转,右转。
抽象类:轮。
类:方向盘,派生自方向盘,公开接口转向
一个是对可以跨不同范围提供的行为进行分类,另一个是对事物的本体建模。
如果您有一些可以被多个类使用的通用方法,那么可以使用抽象类。否则,如果您想让类遵循某些明确的蓝图,可以使用接口。
下面的例子说明了这一点。
Java中的抽象类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | abstract class animals { // They all love to eat. So let's implement them for everybody void eat() { System.out.println("Eating..."); } // The make different sounds. They will provide their own implementation. abstract void sound(); } class dog extends animals { void sound() { System.out.println("Woof Woof"); } } class cat extends animals { void sound() { System.out.println("Meoww"); } } |
以下是一个用Java实现的接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | interface Shape { void display(); double area(); } class Rectangle implements Shape { int length, width; Rectangle(int length, int width) { this.length = length; this.width = width; } @Override public void display() { System.out.println("**** * * * * ****"); } @Override public double area() { return (double)(length*width); } } class Circle implements Shape { double pi = 3.14; int radius; Circle(int radius) { this.radius = radius; } @Override public void display() { System.out.println("O"); // :P } @Override public double area() { return (double)((pi*radius*radius)/2); } } |
简而言之,以下是一些重要的要点:
Java接口中声明的变量默认为final。抽象类可以有非最终变量。
默认情况下,Java接口中声明的变量是静态的。抽象类可以有非静态变量。
默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的一般风格,如private、protected等。
这并不是最初问题的答案,但一旦你知道了它们之间的区别,你就会进入"什么时候使用"的两难境地:何时使用接口或抽象类?什么时候同时使用?
我对OOP的知识有限,但是把接口看作语法上的一个形容词一直对我很有用(如果这个方法是假的,请纠正我)。例如,接口名类似于可以赋予类的属性或功能,而类可以有许多属性或功能:ISerializable、ICountable、IList、ICacheable、IHappy、…
继承用于两个目的:
允许对象将父类型数据成员和方法实现视为自己的。
允许对一种类型的对象的引用被期望引用超类型对象的代码使用。
在支持通用多重继承的语言/框架中,通常不需要将类型划分为"接口"或"抽象类"。然而,流行的语言和框架将允许一个类型将另一个类型的数据成员或方法实现视为自己的,即使它们允许一个类型可以替换任意数量的其他类型。
抽象类可能具有数据成员和方法实现,但只能由不继承任何其他类的类继承。接口对实现它们的类型几乎没有限制,但不能包含任何数据成员或方法实现。
有时候类型可以替换很多不同的东西是很有用的;在其他情况下,对象将父类型数据成员和方法实现视为自己的是有用的。在接口和抽象类之间进行区分,允许在最相关的情况下使用这些功能。
我想再加一个有意义的区别。例如,您有一个包含数千行代码的框架。现在,如果您想使用enhanceUI()方法在代码中添加新特性,那么最好在抽象类中而不是在接口中添加该方法。因为,如果你在一个接口中添加这个方法,那么你应该在所有已实现的类中实现它,但如果你在抽象类中添加这个方法,情况就不一样了。
您可以在接口和抽象类之间找到明显的区别。
接口
接口只包含抽象方法。强制用户在实现接口时实现所有方法。只包含最终变量和静态变量。使用接口关键字声明。接口的所有方法都必须定义为public。一个接口可以扩展,一个类可以实现多个其他接口接口。抽象类
抽象类包含抽象和非抽象方法。
继承时不强制用户实现所有方法吗抽象类。
包含各种变量,包括基本变量和非基本变量
使用abstract关键字声明。
抽象类的方法和成员可以用any来定义可见性。
子类只能扩展单个类(抽象类或具体类)。
抽象类和接口之间的区别代表了实际实现。
接口:它是一个关键字,用来定义一个对象的模板或蓝图,它强制所有子类都遵循相同的原型,对于as实现,所有子类都可以根据需要自由实现功能。
我们应该使用接口的一些其他用例。
两个外部对象之间的通信(我们的应用程序中的第三方集成)通过接口在这里接口作为契约工作。
抽象类:抽象,它是一个关键字,当我们在任何类之前使用这个关键字时,它就变成了抽象类。时主要使用我们需要定义的模板以及一些默认功能的对象是紧随其后的是所有的子类,这样消除了冗余的代码和一个用例,我们可以使用抽象类,如我们希望没有其他类可以直接实例化一个类的对象,只有派生类可以使用的功能。
抽象类的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public abstract class DesireCar { //It is an abstract method that defines the prototype. public abstract void Color(); // It is a default implementation of a Wheel method as all the desire cars have the same no. of wheels. // and hence no need to define this in all the sub classes in this way it saves the code duplicasy public void Wheel() { Console.WriteLine("Car has four wheel"); } } **Here is the sub classes:** public class DesireCar1 : DesireCar { public override void Color() { Console.WriteLine("This is a red color Desire car"); } } public class DesireCar2 : DesireCar { public override void Color() { Console.WriteLine("This is a red white Desire car"); } } |
接口的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public interface IShape { // Defines the prototype(template) void Draw(); } // All the sub classes follow the same template but implementation can be different. public class Circle : IShape { public void Draw() { Console.WriteLine("This is a Circle"); } } public class Rectangle : IShape { public void Draw() { Console.WriteLine("This is a Rectangle"); } } |
重点:
抽象类可以有属性、数据字段、方法(complete /不完整的)。如果方法或属性在抽象关键字中定义,则必须在派生类中重写。(它的工作是紧密耦合的功能)如果在抽象类中为方法或属性定义抽象关键字,则无法定义方法体并为其获取/设置值属性,必须在派生类中重写。抽象类不支持多重继承。抽象类包含构造函数。抽象类可以包含子、函数和属性的访问修饰符。只有抽象类的完整成员可以是静态的。接口只能从另一个接口继承,而不能从抽象类继承,而抽象类可以从另一个抽象类或另一个接口继承。优势:
它是一种契约,强制所有子类执行相同的层次结构或标准。如果各种实现类型相同,并且使用公共行为或状态,则使用抽象类更好。如果我们向抽象类添加一个新方法,那么我们就可以选择提供缺省实现,因此所有现有代码都可以正常工作。它比接口执行速度快。(接口需要更多的时间在相应的类中找到实际的方法。)它可以用于紧密耦合和松散耦合。在这里找到细节……http://pradeepatkari.wordpress.com/2014/11/20/interface-and-abstract-class-in-c-oops/
为了给出一个简单而清晰的答案,设置上下文是有帮助的:当您不想提供完整的实现时,可以同时使用这两种方法。
主要的区别在于接口根本没有实现(只有没有主体的方法),而抽象类也可以有成员和带有主体的方法,即可以部分实现。
根据定义,接口不能有任何方法的实现,并且不能初始化成员变量。
然而,抽象类可以实现方法并初始化成员变量。
当您希望在契约中进行更改时,请使用抽象类。例如,将来您可能需要添加一个新方法。
在这种情况下,如果您决定使用一个接口,当该接口被更改为包含接口时,您的应用程序将在您转储新接口dll时崩溃。
要详细阅读,请访问抽象类和接口之间的差异
许多初级开发人员错误地认为接口、抽象类和具体类是同一事物的细微变化,并且纯粹基于技术原因选择其中一个:我需要多重继承吗?我需要放常用方法的地方吗?除了具体的课程,我还需要为其他事情操心吗?这是错误的,而隐藏在这些问题中的主要问题是:"我"。当您自己编写代码时,您很少会想到其他当前或未来的开发人员正在处理或使用您的代码。
接口和抽象类虽然从技术的角度来看很相似,但是它们具有完全不同的含义和目的。
总结
接口定义了一些实现将为您完成的契约。
抽象类提供了实现可以重用的默认行为。
选择总结接口用于定义公共api抽象类用于内部使用和定义SPIs关于隐藏实现细节的重要性
一个具体的类以一种非常具体的方式做实际的工作。例如,
另一方面,列表的高级用户并不真正关心它是如何实现的,他们应该与这些细节隔离。让我们假设Java没有公开
抽象类位于接口和具体类之间。它应该帮助实现共享公共或无聊的代码。例如,
api和spi
接口是代码不同部分之间的低内聚网关。它们允许库的存在和进化,而不会在内部发生变化时破坏每个库用户。它被称为应用程序编程接口,而不是应用程序编程类。在较小的规模上,它们还允许多个开发人员在大型项目上成功协作,通过良好文档化的接口将不同的模块分离开来。
抽象类是在实现接口时使用的高内聚帮助器,假设有一定程度的实现细节。另外,抽象类用于定义SPIs(服务提供者接口)。
API和SPI之间的区别很细微,但很重要:对于API,重点是谁使用它,而对于SPI,重点是谁实现它。
向API添加方法很容易,API的所有现有用户仍然会编译。向SPI添加方法很难,因为每个服务提供者(具体实现)都必须实现新方法。如果接口用于定义SPI,那么每当SPI契约发生更改时,提供者就必须发布一个新版本。如果使用抽象类,则可以根据现有的抽象方法定义新方法,或者将其定义为空的
尽管Java 8介绍了接口的默认方法,使线之间的接口和抽象类甚至更模糊,这不是以便实现可以重用代码,但是,让它更容易改变接口,提供一个API, SPI(或错误的用于定义SPI而非抽象类)。
使用哪一个?它应该被代码的其他部分公开使用,还是被其他外部代码公开使用?向其添加一个接口,以对公共抽象契约隐藏实现细节,这是事物的一般行为。这个东西应该有多个实现,并且有很多代码是相同的吗?同时创建一个接口和一个抽象的、不完整的实现。是否只有一个实现,而没有其他人使用它?让它成为一个具体的类。"ever"是很长的一段时间,你可以玩得很安全,还可以在上面添加一个界面。一个推论:另一种方法常常是错误的:当使用一个东西时,总是尝试使用您实际需要的最通用的类/接口。换句话说,不要将变量声明为
简而言之,an
同时,一个
或者,如果我们想将其归结为一句话:
抽象类是不能创建对象的类或不能实例化的类。抽象方法使类抽象。需要继承抽象类,以便覆盖在抽象类中声明的方法。对访问说明符没有限制。抽象类可以有构造函数和其他具体方法(非abstarct方法),但是接口不能有。
接口是方法的蓝图/模板。纸上的房子是给定的(接口房子),不同的架构师将使用他们的想法来构建它(实现接口的架构师的类)。它是一个抽象方法、默认方法、静态方法、最终变量和嵌套类的集合。不允许所有成员都是final或public、protected和private访问说明符。不允许创建对象。必须创建一个类,以便使用实现接口并覆盖接口中声明的抽象方法。接口是松散耦合(动态多态性/动态绑定)的一个很好的例子接口实现多态性和抽象。它告诉要做什么,但是如何做是由实现类定义的。如。有一家汽车公司,它希望它所生产的所有汽车的一些功能都是相同的,因此,该公司将会生产一种界面车,它将具有这些功能,而不同类别的汽车(如Maruti Suzkhi, Maruti 800)将覆盖这些功能(功能)。
当我们已经有抽象类时,为什么还要接口?Java只支持多级继承和层次继承,但在接口的帮助下可以实现多重继承。
通常抽象类用于核心,接口用于附加外设。
当您想为车辆创建基类型时,您应该使用抽象类,但是如果您想添加一些不属于车辆基本概念的功能或属性,您应该使用接口,例如您想添加"ToJSON()"函数。
接口具有广泛的抽象范围,而不是抽象类。您可以在传递参数时看到这一点。看这个例子:
如果使用vehicle作为参数,则可以使用它的派生类型之一(bus或car-same category-just vehicle category)。但是当您使用IMoveable接口作为参数时,您有更多的选择。
一个简单而有效的解释php.net抽象类和接口:
An Interface is like a protocol. It doesn't designate the behavior of the object; it designates how your code tells that object to act. An interface would be like the English Language: defining an interface defines how your code communicates with any object implementing that interface.
An interface is always an agreement or a promise. When a class says"I implement interface Y", it is saying"I promise to have the same public methods that any object with interface Y has".
On the other hand, an Abstract Class is like a partially built class. It is much like a document with blanks to fill in. It might be using English, but that isn't as important as the fact that some of the document is already written.
An abstract class is the foundation for another object. When a class says"I extend abstract class Y", it is saying"I use some methods or properties already defined in this other class named Y".
So, consider the following PHP:
1
2
3
4
5 <?php
class X implements Y { } // this is saying that"X" agrees to speak language"Y" with your code.
class X extends Y { } // this is saying that"X" is going to complete the partial class"Y".
?>You would have your class implement a particular interface if you were distributing a class to be used by other people. The interface is an agreement to have a specific set of public methods for your class.
You would have your class extend an abstract class if you (or someone else) wrote a class that already had some methods written that you want to use in your new class.
These concepts, while easy to confuse, are specifically different and distinct. For all intents and purposes, if you're the only user of any of your classes, you don't need to implement interfaces.
在一个接口中,所有的方法都必须是定义,而不是单个方法。
但是在抽象类中必须有一个只有定义的抽象方法,但是其他方法也可以在抽象类中有实现…
接口通常是没有逻辑的类,只是一个签名。而抽象类是那些具有逻辑的类。两者都支持契约作为接口,所有方法都应该在子类中实现,但在抽象中只应该实现抽象方法。什么时候使用接口,什么时候抽象?为什么使用接口?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class Circle { protected $radius; public function __construct($radius) { $this->radius = $radius } public function area() { return 3.14159 * pow(2,$this->radius); // simply pie.r2 (square); } } //Our area calculator class would look like class Areacalculator { $protected $circle; public function __construct(Circle $circle) { $this->circle = $circle; } public function areaCalculate() { return $circle->area(); //returns the circle area now } } |
我们只需要
1 | $areacalculator = new Areacalculator(new Circle(7)); |
几天后,我们将需要矩形、正方形、四边形等的面积。如果是这样,我们是否必须每次都更改代码并检查实例是正方形、圆形还是矩形?OCP说的是接口的代码,而不是实现。解决方案是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Interface Shape { public function area(); //Defining contract for the classes } Class Square implements Shape { $protected length; public function __construct($length) { //settter for length like we did on circle class } public function area() { //return l square for area of square } Class Rectangle implements Shape { $protected length; $protected breath; public function __construct($length,$breath) { //settter for length, breath like we did on circle,square class } public function area() { //return l*b for area of rectangle } } |
现在是面积计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Areacalculator { $protected $shape; public function __construct(Shape $shape) { $this->shape = $shape; } public function areaCalculate() { return $shape->area(); //returns the circle area now } } $areacalculator = new Areacalculator(new Square(1)); $areacalculator->areaCalculate(); $areacalculator = new Areacalculator(new Rectangle(1,2)); $areacalculator->;areaCalculate(); |
这不是更灵活吗?如果我们要编写没有接口的代码,我们将检查每个形状冗余代码的实例。
什么时候使用抽象?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Abstract Animal { public function breathe(){ //all animals breathe inhaling o2 and exhaling co2 } public function hungry() { //every animals do feel hungry } abstract function communicate(); // different communication style some bark, some meow, human talks etc } |
抽象应该用在不需要类实例的时候,有类似的逻辑,需要契约的时候。
下面是对接口和抽象类的基本理解。
抽象类和迭代器的一般思想是由使用这些通用"设置"(某种模板)的其他类(不能单独构造)扩展/实现,这使得为以后扩展它的所有对象设置特定的通用行为变得很简单。
抽象类有规则方法集和抽象方法。扩展类可以在被抽象类扩展后包含未设置的方法。当设置抽象方法时——它们是由稍后扩展它的类定义的。
接口具有与抽象类相同的属性,但是只包含抽象方法,这些方法可以在其他类/es中实现(并且可以实现多个接口),这就创建了一个更持久的方法/静态变量定义。与抽象类不同,您不能添加自定义的"常规"方法。
我们在接口和抽象类之间有各种结构/语法上的差异。还有一些不同之处
基于[1]场景的差异:
抽象类用于限制用户创建父类对象的场景,我们相信将来会添加更多的抽象方法。
当我们确信不能再提供抽象方法时,就必须使用接口。然后只发布一个接口。
[2]概念的区别:
"我们是否需要在未来提供更多的抽象方法",如果是,让它抽象类,如果不是,让它接口。
(在java 1.7之前最合适和有效)