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