抽象类和接口基本上是面试必问的一个问题,因为用的实在是太普遍了,用好抽象类和接口是开发者必备的技能。但是真正用好二者确实不太容易。抽象类和接口是面向对象编程中的两个核心概念,它们旨在帮助开发者更好地组织和管理代码,并提高代码的可维护性和可扩展性。在本文中,我们将详细介绍抽象类和接口的区别和使用场景,并通过PHP语言给出代码演示。
抽象类是使用关键字abstract来定义的,而接口是使用关键字interface来定义的。
抽象类可以包含普通方法和抽象方法,而接口只能包含抽象方法。
抽象类可以被继承,子类可以继承父类的属性和方法,并且必须实现父类中的抽象方法。而接口则不能被继承,它只能被实现,实现了接口的类必须实现接口中所有的抽象方法。
抽象类可以包含构造方法,而接口不可以。
抽象类中的成员方法可以包含public、protected和private三种访问修饰符,而接口中的成员方法只能包含public访问修饰符。
抽象类强调“是不是”,主要用于定义一些基础类,而接口强调“能否”,主要用于定义一些可替换的类或行为。
抽象类通常用于定义一些基础类,它们的主要作用是为派生类提供公共的基础方法和属性。抽象类可以包含普通方法和抽象方法,其中普通方法可以提供默认实现,而抽象方法则需要子类去实现。除此之外,抽象类还可以包含protected和private成员变量和方法,以及构造方法。下面是一个用抽象类定义的基础类的例子:
abstract class Shape{
protected $color;
public function setColor($color){
$this->color = $color;
}
abstract public function getArea();
}
class Circle extends Shape{
protected $radius;
public function __construct($radius){
$this->radius = $radius;
}
public function getArea(){
return pi()*pow($this->radius,2);
}
}
class Rectangle extends Shape{
protected $width;
protected $height;
public function __construct($width,$height){
$this->width = $width;
$this->height = $height;
}
public function getArea(){
return $this->width*$this->height;
}
}
在上面的例子中,我们用抽象类Shape定义了一个基础图形类,其中包含了protected属性$color和abstract方法getArea()。然后我们用Circle和Rectangle来继承Shape,并实现了getArea()方法。
接口通常用于定义一些行为规范,它们的主要作用是约束各个实现类的行为,从而提高程序的可扩展性和可替换性。接口只包含抽象方法,没有属性和方法的实现。下面是一个用接口定义的日志记录器的例子:
interface Logger{
public function log($msg);
}
class FileLogger implements Logger{
public function log($msg){
//将日志写入文件
}
}
class DatabaseLogger implements Logger{
public function log($msg){
//将日志写入数据库
}
}
在上面的例子中,我们用接口Logger定义了一个日志记录器的规范,其中只包含一个抽象方法log()。然后我们用FileLogger和DatabaseLogger来实现Logger,并实现了log()方法。
下面是一个通过抽象类Shape和接口Logger来实现一个图形绘制和日志记录的例子:
abstract class Shape{
protected $color;
public function setColor($color){
$this->color = $color;
}
abstract public function getArea();
}
interface Logger{
public function log($msg);
}
class Circle extends Shape{
protected $radius;
public function __construct($radius){
$this->radius = $radius;
}
public function getArea(){
return pi()*pow($this->radius,2);
}
}
class Rectangle extends Shape{
protected $width;
protected $height;
public function __construct($width,$height){
$this->width = $width;
$this->height = $height;
}
public function getArea(){
return $this->width*$this->height;
}
}
class Canvas{
private $shapes = [];
public function addShape(Shape $shape){
$this->shapes[] = $shape;
}
public function draw(Logger $logger){
foreach($this->shapes as $shape){
$area = $shape->getArea();
$logger->log("The area of shape is ".$area);
}
}
}
class FileLogger implements Logger{
private $filename;
public function __construct($filename){
$this->filename = $filename;
}
public function log($msg){
file_put_contents($this->filename,$msg."\n",FILE_APPEND);
}
}
$circle = new Circle(5);
$circle->setColor('red');
$rectangle = new Rectangle(10,20);
$rectangle->setColor('blue');
$canvas = new Canvas();
$canvas->addShape($circle);
$canvas->addShape($rectangle);
$logger = new FileLogger('log.txt');
$canvas->draw($logger);
在上面的例子中,我们定义了一个抽象类Shape和一个接口Logger,并用Circle和Rectangle来继承Shape,FileLogger来实现Logger。然后我们通过Canvas类来实现图形绘制,并且记录日志。在最后,我们创建了一个FileLogger对象来将日志写入到文件中。
通过以上的例子,我们可以看出抽象类和接口在代码中的作用和使用场景。抽象类用于定义一些基础类,而接口用于定义一些行为规范。它们都是为了让代码更加模块化、可维护和可扩展。因此,在实际开发中,我们应该根据业务需求合理地使用抽象类和接口,以提高代码质量和可维护性。