关于抽象类和接口的初步理解
什么是抽象类
抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类。
抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。子类可以通过继承抽象类并通过实现抽象类中的所有抽象方法,使抽象类具体化。
如果子类需要实例化,前提是它实现了抽象类中的所有抽象方法。如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化。
引用链接
接口(Interface)—— 定义行为
抽象类(Abstract Class) —— 实现行为
具体类(class)——执行行为
引用链接
抽象类就是一个类的服务提供商,拥有众多服务,你不用必须用,当需要的时候你来用就可以,如果你觉得不提供服务不满意,你还可以自己来做。
抽象方法是必须实现的方法。就象动物都要呼吸。但是鱼用鳃呼吸,猪用肺呼吸。
动物类要有呼吸方法。怎么呼吸就是子类的事了。
为什么要使用抽象类
按照我目前的知识理解:
保持程序的一致性
抽象类限制了实现的方法,也是为了保持一致性
增加代码重用性,例如一些公共类不需要实现,只需要调用里面的方法就可以了。
现在有很多讨论和建议提倡用interface代替abstract类,两者从理论上可以做一般性的混用,但是在实际应用中,他们还是有一定区别的。抽象类一般作为公共的父类为子类的扩展提供基础,这里的扩展包括了属性上和行为上的。而接口一般来说不考虑属性,只考虑方法,使得子类可以自由的填补或者扩展接口所定义的方法,就像JAVA王子所说的事件中的适配器就是一个很好的应用。
用一个简单的例子,比如说一个教师,我们把它作为一个抽象类,有自己的属性,比如说年龄,教育程度,教师编号等等,而教师也是分很多种类的,我们就可以继承教师类而扩展特有的种类属性,而普遍属性已经直接继承了下来。
而接口呢~还是拿教师做例子,教师的行为很多,除了和普通人相同的以外,还有职业相关的行为,比如改考卷,讲课等等,我们把这些行为定义成无body的方 法,作为一个集合,它是一个interface。而教师张三李四的各自行为特点又有不同,那么他们就可以扩展自己的行为body。从这点意义上来说,interface偏重于行为。
怎样使用抽象类
<?php
abstract class Shape{ //这是一个抽象类,不能实例化
protected $color; //抽象类里面一般都是使用protected来保护属性,这是封装的意义
public function __construct($color = 'red') { //抽象类可以使用构造方法,主要是为了方便代码重用,构造方法里面也可以使用默认参数,当没有配置参数的时候,就会使用默认的参数,写法如上
$this->color = $color;
}
public function getColor() { //只是为了演示需要的一个方法
return $this->color;
}
abstract public function getArea(); //构造方法是为了限制代码,对于继承这个构造类的子类,必须限制拥有这个构造方法,主要为了保持代码一致性。
}
class Square extends Shape{
protected $length = 4;
public function getArea() {
return pow($this->$length, 2);
}
}
class Circle extends Shape{ //这里因为没有构造方法getArea,所以代码允许会报错的。
}
$shape = new Square();
var_dump($shape);
?>
接口和抽象类
抽象类不能被直接实例化,抽象类中只定义子类需要的方法,子类可以继承并且通过实现其中的抽象方法,使抽象类具体化。例如一个名为media的类,他是用于描述各种公开出版的共同性质,因为media不表示真实的实体,而是一些相似实体的泛化表示,所以不实例化,这样就需要声明为抽象类,然后再由各种的派生的Media类继承此抽象类
抽象类的每个子类都必须实现抽象类中的所有抽象方法,或者把他们自身也声明为抽象方法。
扩展类不仅仅负责简单实现抽象类的方法,还必须重新声明方法,新的方法不能比抽象方法的访问控制更严格,新的实现方法的参数个数应该和抽象方法的参数个数一样。
接口定义了实现某种服务的一般规范,声明了必须的函数和常量,但是不指定如何实现。关键是要建立必须实现的一组一般原则,只有满足了这些原则才能说实现了这个接口。
抽象类提供了具体实现的标准,而接口则是纯粹的模板。接口只能定义功能而不包含实现的内容。
任何实现接口的类都要实现接口中所定义的所有方法,否则类必须声明为abstract。
实现接口的类接受他的继承的类以及实现的接口的类型。
什么时候用接口,什么时候用抽象类
如果要创建一个模型,这个模型将由一些紧密相关的对象引用,就可以采用抽象类,如果要创建将由一些不想关的对象采用的功能,应该用接口。
如果必须从多个来源继承行为,就是用接口。
如果知道所有类都会共享一个公共的行为实现,就使用抽象类,并在其中实现行为。接口无法实现。
一个类只能extends一个父类,但可以贯彻多个接口。
接口作用一:
接口类就是一个类的领导者,指明方向,子类必须完成它指定方法。
当有很多人一起开发一个项目时,可能都会去调用别人写的一些类,那你就会问,我怎么知道他的某个功能的实现方法是怎么命名的呢,这个时候php接口类就起到作用了,当我们定义了一个接口类时,它里面的方式是下面的子类必须实现的,比如
interface Shop
{
public function buy($gid);
public function sell($gid);
public function view($gid);
}
class BaseShop implements Shop
{
public function buy($gid)
{
echo '你购买了ID为 :' . $gid . '的商品';
}
public function sell($gid)
{
echo '你购卖ID为 :' . $gid . '的商品';
}
public function view($gid)
{
echo '你浏览了ID为 :' . $gid . '的商品';
}
}
接口作用二:
有时候,我们需要设计一个物品,比如shape,这个shape有不同的形状,有不同的颜色,可作不同的运动,等等。当然我们可以把这些都放在一个类里面,但这样,如前面说的,只是过程编程,不是OO编程。你会说,像上面例子一样,做一个抽象类,然后在子类里实现所有的功能。好象不错,进步了。这样子类里面要实现形状,颜色,运动等功能,OK吗?记住,OO里面还有一条原则,为了最大程度的做到代码重用,一个类里最好只实现一个功能,也就是说,一个类做形状,一个类做颜色,一个类做运动 。这样如果其他的类要用到颜色的功能时,我们就可以重用这个颜色类,同理,这样我们可以很容易的重用运动类,形状类,等等。
但这样问题出来了,现在我们要用到上面所有的功能,但又分散在三个类里面,怎么办?这时我们就要用到抽象类和接口了。选定一个跟shape关联最大的一项–形状,把它做成抽象类, 其他两样,把它们做成接口,然后在子类里面extends一个抽象类,再implements两个接口就行了。如:
class Square extends Shape implements 颜色, 运动, ... {
...
}
抽象类作用一:
抽象类就是一个类的服务提供商,拥有众多服务,你不用必须用,当需要的时候你来用就可以,如果你觉得不提供服务不满意,你还可以自己来做。
这里是一个例子,想上面一样我定义了一个商店类,抽所了它所有像的部分,买(buy),卖(sell),看(view),并且抽象类里都实现了这些方法,那么继承它的子类就自动获得了这些方法,子类就做它自己独特的东西,减少代码的重复,提高复用性。
abstract class BaseShop
{
public function buy($gid)
{
echo '你购买了ID为 :' . $gid . '的商品';
}
public function sell($gid)
{
echo '你购卖ID为 :' . $gid . '的商品';
}
public function view($gid)
{
echo '你浏览了ID为 :' . $gid . '的商品';
}
}
class BallShop extends BaseShop
{
var $itme_id = null;
public function __construct()
{
$this->itme_id = 2314;
}
public function open()
{
$this->sell($this->itme_id);
}
}
抽象类作用二:
在抽象类里面设置抽象方法
在oo设计时,会把一些通用的方法放在一个类里,但考虑到子类继承时的差异性,又不能把它事先实现,就只好用到这个抽象类或接口了。这里很清楚的显示了在抽象类里,我们贯彻了设原用到点setCenter()的方法,这样,当子类继承它时,就不用再重复写这个设原点的方法了。那么为什么draw的方法要设定成抽象方法呢?这是因为不同的子类要用不同的实现方法。
abstract class Shape
{
function setCenter($x, $y)
{
$this->x = $x;
$this->y = $y;
}
abstract function draw();
protected $x, $y;
}
参考:http://chengxudaren.com/index.php?act=article&op=detail&a_id=152
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。