我们可以使用简单的继承或接口而不是抽象。 为什么我们需要在PHP中使用抽象?我们如何使用抽象隐藏基本功能?我很困惑使用抽象和接口和继承。哪里用哪个? 请帮助理解我。
答案 0 :(得分:7)
我认为首先澄清术语非常重要,以便更精细地回答这个问题。
abstract
,则此实现可以由抽象类本身提供,或者由扩展类提供。它还允许实现属性和私有/受保护方法,因为这里的继承就像一个基类,而不仅仅是一个要求。所以回答这个问题," 为什么我们在PHP "中有抽象类,因为它很有用。您可能会首先将这些视为棘手的想法,但它们实际上可以协同工作以提供联合效用。
考虑到有时候界面不足以创建有用的实现。接口只能强制存在方法,并且其签名与实现的接口兼容。例如,您可能希望提供接口的默认实现。
interface Device {
public function input(Stream $in);
public function output(): Stream;
}
abstract class DefaultDevice implements Device {
protected $buffer = "";
public function input(Stream $in) {
$this->buffer .= $in->read(1024);
$this->process();
}
abstract protected function process();
}
所以现在任何扩展DefaultDevice
的类都可以选择覆盖input
方法的实现。即使接口不需要它,它也必须实现process
方法。这意味着实现Device
接口的其他类可以向后兼容,这仍然是一个实现细节。
将实现与规范分开通常是编写良好的软件的关键属性。
看看Device
界面本身就是一个很好的例子。我们依靠input
方法接受Stream
类型,output
方法返回Stream
类型。由于Stream
本身实际上可以是一个接口,这意味着任何实现Stream
的类型都是可以接受的。所以我可以创建我自己的类并实现Stream
接口,而不会破坏此代码。
class CustomStream implements Stream {
public function read($bytes = 1024) {
/* implementation */
}
public function write($data) {
/* implementation */
}
}
$device->input(new CustomStream); // this will not throw an error
答案 1 :(得分:2)
abstract
类用于提供一组数据成员或方法,使其可用于继承自它的类,即使基类不是特别有用(并且永远不应该自己实例化) )没有继承的实现。
从这里继承接管。
另一方面,interface
是提供一组实现规则,要求每个使用该接口的类实现其中的规范。实现相同接口的类不需要相互继承,它们实现了接口,因此可以在需要该组功能的任何应用程序中使用它们。
答案 2 :(得分:1)
正如练习一样,我们可以尝试创建一些类来处理几何形状。
基类:
class Shape
{
public function draw()
{
}
}
上面的代码片段中只描述了基类的相关部分。当然,它应该有属性来存储它的位置,线条颜色等和方法(至少是构造函数)。
一些派生类:
class Circle extends Shape
{
public function draw()
{
// the code to draw a circle
}
}
class Rectangle extends Shape
{
public function draw()
{
// the code to draw a rectangle
}
}
我们可以在基类draw()
中为方法Shape
提供实现吗?
当然不是。 Shape
是通用的,它并不仅仅意味着“圆圈”或“矩形”或“三角形”。没有办法为Shape::draw()
提供合理的实施,因为我们甚至不知道它代表什么样的形状。
为Shape::draw()
提供空实现是否可以?
显然是。然而,在第二个想法,很明显,这是不安全的。无法绘制扩展Shape
并且不为方法draw()
提供其自己的实现的类的对象。
因为类Shape
无法为方法shape
提供合适的实现,所以它应该以某种方式向派生类发出信号,并强制它们提供实现。
它表示这种情况的方式是abstract
关键字。 abstract
方法告诉类的读者该类无法提供实现,因为它太通用了,它将此责任委托给扩展它的每个类。
没有完全定义具有abstract
方法的类。这就是为什么它是abstract
类并且无法实例化的原因。