当我们谈论概念层面的面向对象编程概念时,假设我们要创建 Car 对象。因此我们需要设计父类。假设如果你要做那部分,你会怎么做?
你会使用类还是接口还是抽象类?那你为什么要使用界面?为什么我们不能对类/抽象类做同样的事情?使用接口作为父级有什么好处?
当我们谈论概念层面的面向对象编程概念时,假设我们要创建 Car 对象。因此我们需要设计父类。假设如果你要做那部分,你会怎么做?
你会使用类还是接口还是抽象类?那你为什么要使用界面?为什么我们不能对类/抽象类做同样的事情?使用接口作为父级有什么好处?
当您不想实例化超类但又想实现一些功能时,您需要抽象类。
单亲继承时需要接口,不能使用抽象类。如果 Java 中存在多重继承,我假设您是根据您使用的术语谈论的,那么接口将是多余的。
好吧,使用您的 Car 对象,我将尝试通过一个真实世界的示例来解释这个概念。
想象一下,您是一家制造汽车零件的小公司 (A),您为一家较大的公司 (B) 制造汽车零件,该公司是您的客户,这些零件将被其他汽车制造商使用。
B 公司必须确保您的产品符合标准,并且与所有汽车制造商兼容。
这是你的界面。
接口用于定义一些标准化的方法或属性,以我们为例,我们可以定义一块在每个角落有4个孔,用于固定在另一家公司制造的另一块上。
抽象有点不同,抽象比接口更具体(我同意这是一种废话),但它们是具体的,因为它们直接实现(例如接口)功能,而抽象类永远不能 被实例化.
抽象类主要用于定义一些基本或共享的功能以使其干燥。
因此,您可以创建一个扩展抽象类并实现接口的类。
这是一个例子:
interface Vehicle {
protected $engine;
protected $wheels;
public function startUp();
public function stop();
}
您的 Vehicle 接口定义了需要具有引擎和车轮(任意数量)的 Vehicle。
abstract class Car implements Vehicle {
protected $wheels = 4;
public function startUp() {
$this->engine->startUp();
}
public function stop() {
$this->engine->stop();
}
}
因为startUp()
andstop()
只是 Engine 对象的代理,我们可以将它们放在抽象类中,以便在所有扩展类中重用。我们将 Car 类设置为有 4 个轮子。
class Renault extends Car {
protected $color = 'yellow';
}
这里我们只需要扩展 Car 抽象类,我们添加一些颜色,因为它很酷。
现在,假设我们想把我们的雷诺带到洗车站,因为我们正在实现一个已知的接口,洗车站将能够在不知道我们的车辆是雷诺的情况下工作,但只知道它是一辆车。
这是一个非常基本的示例,它可以设计得更好,但它应该向您展示它是如何工作的。
不需要接口,至少 PHP 不需要任何类来实现任何接口,但是,您应该使用它们,这通常是一种很好的做法,它可以帮助您编写 API、单元测试或在其他开发人员之间共享一些代码。
冒着变得太深入甚至太夸张的风险,我会尽我所能回答你的问题。
在您提供的示例的上下文中,具有抽象“车辆”类的“汽车”类将是最合适的解决方案。这是因为如果您允许,汽车可以成为一个非常复杂的物体。您可能希望编写一个车辆类来抽象出一些任意的更高级别的数据,而不是将所有内容都打包到汽车类中。如果您计划稍后实现更多功能或创建其他类型的车辆,例如:飞机,这将非常方便。一个抽象类让你的应用程序更加灵活;如果您觉得需要,您还可以抽象车辆类。从概念上讲,OOP 是关于在抽象和分类方面将代码与我们所有人的思维方式联系起来。但是,如果您正在实现简单的功能集,那么简单的类就足够了。
界面是完全不同的野兽。接口(就计算而言)是一种概念工具,允许程序员在实现和应用程序之间创建一个分离层。例如,如果你想创建一些程序来与声卡通信,你应该创建一个接口类。事实上,这本质上就是设备驱动程序。一些语言,如 Java,有一个内置的接口结构来表示相同的概念。但是,理论上您可以使用任何语言创建界面。
您可以使用一个简单的类来实现简单的功能。请记住:类用于对象的实例化;抽象(或基)类用于从类中抽象出数据以创建基本功能。在这两种情况下,它们都处理与应用程序实现不直接相关的代码。但是,这些概念工具不能互换使用。这就是软件工程师和程序员的区别;分别知道何时使用正确的工具和知道如何使用它们。
正如我之前提到的,应该使用接口将实现与应用程序分开。如果您与设备驱动程序通信,您不想混入 GUI 代码。接口就像两者之间的联络人。从技术上讲,接口是“实现”的,而不是继承自;然而,在没有明确接口结构的语言中,类用于模拟概念,因此将被继承。
我有一个简单的解释,假设你有一个扩展 A 的 B 类。现在你想在 B 类中进行克隆或者你想进行排序。那么现在你会做什么?如果你已经创建了一个 Clonable 类/Comparable 类,你如何在 B 中使用它,因为 B 已经扩展了 A。所以你的解决方案是创建另一个扩展可克隆类的 D 类。创建另一个扩展 D 的类 E(以使用克隆方法)然后....意味着因为java不支持多重继承,所以您必须不使用任何类来执行dis..但是当您将Clonable定义为接口时,您不需要做的只是在Ur中实现它B 类。即不需要额外的编码。这是我为什么要制作接口的解释。如果我在某处错了,请纠正我。谢谢。
当您有一些概括其他实体但没有“现实世界”化身的概念时,抽象类很有用。
假设您Car
的程序中有类,并且您将拥有HummerH2
,ToyotaCamry
和DaewooMatiz
派生自Car
. Car
是Some-Abstract-Car,任何汽车都属于Car
类,但Car
类本身并不表示任何真正的汽车。
所以你可以定义Car
类如下:
abstract class Car
{
public abstract void Move();
public abstract void Stop();
public abstract int GetMaximumSpeed();
public int GetVehicleID()
{
return vehicleID;
}
protected int vehicleID;
}
然后派生出你HummerH2
,ToyotaCamry
并DaewooMatiz
从Car
和实施Move()
,Stop()
和GetMaximumSpeed()
那里。请注意,Car
类将强制其子类具有vehicleID
字段。
接口类似于抽象类,只是不能在接口中声明字段。接口用于声明类必须实现的一些公共功能。
在我们的例子中,我们可以声明接口 IMovable:
interface IMovable
{
void Move();
void Stop();
abstract int GetMaximumSpeed();
}
然后从 IMovable 继承 Car 类:
abstract class Car: IMovable
{
public int GetVehicleID()
{
return vehicleID;
}
protected int vehicleID;
}
请注意,现在Car
必须实现的子类Move()
和Stop()
方法。
而且我们可以定义一些Ship
将实现IMovable
接口的类。在这种情况下,无论它是汽车还是轮船或任何实现接口,两者Ship
都Car
可以作为对象移动,而无需任何对象。IMovable
IMovable
PS:当然,当您编写一些只有一种汽车的简单游戏时,您可以定义非抽象类Car
并使用它。