转载链接
1.https://www.cnblogs.com/songanwei/p/9389005.html#!comments
2.https://blog.csdn.net/qq_22630169/article/details/103490595
3.https://www.cnblogs.com/jimz/p/9375261.html
4.https://www.php.net/manual/zh/language.oop5.interfaces.php
1.abstract
<?php
// 1.声明抽象方法的必须声明为抽象类
//2.抽象类不能被实例化 new AbstractClass();会报错
//3.抽象方法不能定义具体功能实现,只是声明其调用方式,不能呢过定义其具体功能实现
abstract class AbstractClass{
abstract protected function getValue();
abstract protected function getPrefixValue($prefix);
public function printOut()
{
print $this->getValue();
}
}
//继承一个抽象类的时候,子类必须实现父类的抽象方法
//这些访问控制必须和父类一样或者更为宽松
//父类中的抽象方法必须和子类中实现方法的参数类型和数量一致(有待确认,可以加默认参数)
//例如,子类的实现的抽象方法中定义一个可选参数,而父类中声明没有,则两者并无冲突;父类抽象方法有,子类没有也可以
class ConcreteClass1 extends AbstractClass{
protected function getValue($value="")
{
return "ConcreteClass1";
}
public function getPrefixValue($prefix)
{
// TODO: Implement getPrefixValue() method.
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass{
protected function getValue()
{
// TODO: Implement getValue() method.
return "ConcreteClass2";
}
public function getPrefixValue($prefix,$separator="")
{
// TODO: Implement getPrefixValue() method.
return "{$prefix}ConcreteClass2".$separator;
}
}
$class1 = new ConcreteClass1();
$class1->printOut();
echo $class1->getPrefixValue("FOO_");
$class2 = new ConcreteClass2();
$class2->printOut();
echo $class2->getPrefixValue("FOO_","ON");
2.interface
<?php
//接口通过interface关键字定义的,定义的方法都是空的
//接口中的方法必须是public公有的,这是接口的特性
//接口使用extends可以被继承
//接口中可以定义常量,和类常量的使用完全相同,但是不能被子类或者子接口覆盖ia
interface ITemplate
{
const a = "ITemplate Interface constant";
public function setVariable($name,$var);
public function getHtml($template);
public function __construct();
}
//echo ITemplate::b;
interface NTemplate{
const b = "NTemplate Interface constant";
public function next();
public function getHtml($template);
}
interface IITemplate extends ITemplate{
public function II(Baz $baz);
}
//实现一个接口,使用implements操作符号
//类继承接口 必须全部实现接口中的方法
//类可以实现多个接口,使用逗号分隔多个接口的名称
//类要实现接口,必须和接口中定义的方法完全一致
class Template implements iTemplate ,NTemplate,IITemplate
{
private $vars = array();
public function __construct()
{
}
public function setVariable($name, $var)
{
// TODO: Implement setVariable() method.
$this->vars[$name] = $var;
}
public function getHtml($template)
{
// TODO: Implement getHtml() method.
var_dump($template);
}
public function Next()
{
}
public function II(Baz $baz)
{
// TODO: Implement II() method.
}
}
echo Template::a;
3.区别
相同:
1.都不能实例化
2.子类必须实现定义的抽象方法
不同:
1.抽象类由abstract定义,接口由interface定义
2.抽象类的方法可以是public,protected,private,而intreface的访问控制只能是public
3.抽象类中可以定义普通成员变量,接口不能
4.抽象类中可以写具体实现方法(包括构造函数),而接口只能声明函数名称,没有函数实体,必须是抽象的
5.抽象类使用extends单继承;接口使用implements 实现,可以多继承,使用“,”分隔;并且接口之间可以使用extends继承
6.抽象类中定义的方法和子类可以扩展,而interface中声明的方法必须一致
4.应用场景
1.abstract使用场景
通常,在子类和父类之间存在逻辑上的层次结构是应当使用抽象类,而在希望支持差别较大的两个或多个对象之间的特定交互行为时,就应当使用接口。
创业做网站
到底用什么数据库? mysql, oracle,sqlserver,postgresql?
这样:先开发网站,运行再说.
先弄个mysql开发着,正式上线了再数据库也不迟
引来问题:
换数据库,会不会以前的代码又得重写?
答:不必,用抽象类
开发者,开发时,就以db抽象类来开发.
*/
abstract class db {
public abstract function connect($h,$u,$p);
public abstract function query($sql);
public abstract function close();
}
下面这个mysql类,严格实现了db抽象类
试想: 不管上线时,真正用什么数据库
我只需要再写一份如下类
class oracle extends db {
}
class mssql extends db {
}
class postsql extends db {
}
业务逻辑层不用改?
为什么不用改?
因为都实现的db抽象类.
我开发时,调用方法不清楚的地方,我就可以参考db抽象类.
反正子类都是严格实现的抽象类.
*/
class mysql extends db {
public function connect($h,$h,$u) {
return true;
}
public function query($sql) {
}
public function close() {
}
}
Thinkphp框架中就使用abstract定义的
2.intreface使用场景
当多个对象不能抽象出共同的父类,但是有共同的行为,这种情况下就需要将这种行为封装成接口。比如登记这种行为:人,汽车,房子都需要登记,但是这三类没有共同的特征,所以要将登记这一行为封装成一个接口。再如:电脑的USB接口使用,如果符合USB接口规范,就可以插进去,并且读取或写入数据,但是 手机,U盘,MP3他们不是同一种类型,所以要将USB接口单独封装出来。
/*
接口 就更加抽象了
比如一个社交网站,
关于用户的处理是核心应用.
登陆
退出
写信
看信
招呼
更换心情
吃饭
骂人
捣乱
示爱
撩骚
这么多的方法,都是用户的方法,
自然可以写一个user类,全包装起来
但是,分析用户一次性使不了这么方法
用户信息类:{登陆,写信,看信,招呼,更换心情,退出}
用户娱乐类:{登陆,骂人,捣乱,示爱,撩骚,退出}
开发网站前,分析出来这么多方法,
但是,不能都装在一个类里,
分成了2个类,甚至更多.
作用应用逻辑的开发,这么多的类,这么多的方法,都晕了.
*/
interface UserBase {
public function login($u,$p);
public function logout();
}
interface UserMsg {
public function wirteMsg($to,$title,$content);
public function readMsg($from,$title);
}
interface UserFun {
public function spit($to);
public function showLove($to);
}
/*
作为调用者, 我不需要了解你的用户信息类,用户娱乐类,
我就可以知道如何调用这两个类
因为: 这两个类 都要实现 上述接口.
通过这个接口,就可以规范开发.
*/
/*
下面这个类,和接口声明的参数不一样,就报错,
这样,接口强制统一了类的功能
不管你有几个类,一个类中有几个方法
我只知道,方法都是实现的接口的方法.
*/
class User implements UserBase {
public function login($u) {
}
}
?>
备注:这道题的思路是先从总体解释抽象类和接口的基本概念,然后再比较两者的语法细节,最后再说两者的应用区别。
比较两者语法细节区别的条理是:先从一个类中的构造方法、普通成员变量和方法(包括抽象方法),静态变量和方法,继承性等6个方面逐一去比较回答,接着从第三者继承的角度的回答,特别是最后用了一个典型的例子来展现自己深厚的技术功底。