/**
* 作者:xianhenyuan
* 关于作者:公号【会飞的老司机】、网络项目【798项目矩阵】主理人。
*/
interface接口类
用一个常见的CRUD的例子来感受下 interface接口类
/**
* 数据库方法模板
* Interface SQLMethodsInterface
*/
interface SQLMethodsInterface{
public function insert();
public function delete();
public function save();
public function select();
}
/**
* 扩展的前置操作,用来后面体现多继承
* Interface BeforeInterface
*/
interface BeforeInterface{
function beforeAction();
}
如上 方法模板 的代码,interface
用来描述一个类或者多个类的共同行为。
当下面的子类继承的时候,也可同时继承多个 interface
,但必须实现所有被继承的 interface
中定义的所有方法(约束的作用)。
也就是说如果你属于这个类,就必须遵守我的规矩,实现我的定义,具体怎么实现我就不管了。
用代码来感受下:
/**
* 同时继承并实现 SQLMethodsInterface、BeforeInterface
* Class XXXDbClass
*/
class XXXDbClass implements SQLMethodsInterface,BeforeInterface
{
function __construct()
{
echo '<pre/>';
$this->beforeAction();
}
function beforeAction()
{
var_dump('我是 beforeAction 方法');
}
function insert()
{
var_dump('我是 insert 方法');
}
function delete()
{
var_dump('我是 delete 方法');
}
function save()
{
var_dump('我是 save 方法');
}
function select()
{
var_dump('我是 select 方法');
}
}
看到这里你可能就会有疑问了,为什么 interface
不实现这些共同的行为呢?
其目的是为了解耦!
用代码来感受下:
/***
* Class MyClass
*/
class MyClass{
private $SQLInterface = null;
public function __construct(SQLMethodsInterface $SQLInterface)
{
$this->SQLInterface = $SQLInterface;
}
public function select(){
$this->SQLInterface->select();
}
}
$MyClassObject = new MyClass(new XXXDbClass());
$MyClassObject->select();
如果在 MyClass
中使用到了数据库存储,这时只需要将 SQLMethodsInterface接口
注入到 MyClass
中即可。
后续如果需要调整为其他类型的数据库存储,MyClass
的代码是不需要做任何改动的。
abstract抽象类
当你发现一个方法的代码在一个类或者多个类重复写的时候,就可以考虑用抽象类来实现它了。
上面这句话可能会给你带来疑问,公共的方法我写在一个公共类里,谁用谁继承不就好了嘛,干嘛还要用抽象类?
这个问题来说说抽象类的另外一个好处:约束。
抽象类给我的感觉有点像是对于接口类的一个补充,某些角度上跟接口类很像,子类在继承的时候必须定义或实现其父类的所有抽象方法。
这样的约束省去了我们编写公共类之后还要再去定义一个接口类(继承了公共类,子类没去继承和实现接口怎么办?)
用代码来感受下:
<?php
/**
* Class AbstractDemoClass
*/
abstract class AbstractDemoClass{
private $age;
public function setAge($age){
$this->age = $age;
}
public function getAge(){
return $this->age;
}
abstract function checkAge();
}
/**
* 继承的子类必须实现checkAge方法
* Class XXXStandardClass
*/
class XXXStandardClass extends AbstractDemoClass{
const ageMax = 60;
const ageMin = 50;
public function checkAge()
{
if ($this->getAge() < self::ageMin || $this->getAge() > self::ageMax){
return '年龄不合适';
}
return '完美';
}
}
$XXXStandardClassObject = new XXXStandardClass();
$XXXStandardClassObject->setAge(25);
echo $XXXStandardClassObject->checkAge();
接口类和抽象类各自的特点
interface的特点:
interface
接口不能被实例化。- 子类使用
implements
继承。 - 子类必须实现继承的
interface
中定义的所有方法。 interface
接口的方法只需声明,不能定义其具体的实现,且访问控制只能被定义为public
(不能用private、protected修饰符)。interface
接口类中不能定义属性。- 子类通过
implements
继承interface
接口,同时必须实现interface
接口类中定义的所有方法。 - 子类可以继承多个
interface
接口。
abstract的特点:
abstract
抽象类不能被实例化。- 抽象类只能被继承,使用
extends
(子类只能继承一个父类)。 - 当一个类里面如果存在一个抽象方法那么这个类必须被定义为抽象类。
- 被定义为
abstract
抽象的方法只需声明调用方式,不能定义其具体的实现。 abstract
抽象方法的访问控制不能被定义为私有(private
),只能被定义为protected
和public
。abstract
抽象类中可以定义属性。- 子类继承一个抽象类的时候,必须定义或实现其父类的所有抽象方法,所有方法的访问控制必须和父类保持一直或者更为宽松。
- 可以在子类中定义父类方法中不存在的可选参数,但是新增的不存在的参数要有默认值。
总结
interface
用来描述一个类或者多个类的共同行为,约束了子类必须实现其定义的方法。
换言之,当需要保证所有开发人员都遵守一套规则的时候,可以考虑使用 interface
定义;
abstract
也可用来描述一个类或者多个类的共同行为,约束了子类必须定义或实现其定义的抽象方法。同时可以在抽象类中提供一些编写好的方法供子类复用,还可以定义类属性。
换言之,在保证约束的同时还需要提供一些编写好的公共方法时,或者需要定义类属性时,可以使用 abstract
来定义。
总的来看抽象类也好,接口类也罢
其目的是为了更好的约束、复用,减少编写重复代码的无用功