类与类之间有一种父与子的关系,子类继承父类的属性和方法,称为继承。在继承里,子类拥有父类的方法和属性,同时子类也可以有自己的方法和属性。
```
<?php
/**
* User: 三千
* Date: 16/3/16
* Time: 下午4:17
*/
class person{
public $name = 'Tom';
public $gender;
static $money = 10000;
public function __construct(){
echo '这里是父类',PHP_EOL;
}
public function say(){
echo $this->name,"\t is ",$this->gender,"\r\n";
}
}
class family extends person{
public $name;
public $gender;
public $age;
static $money = 1000;
public function __construct(){
parent::__construct();
echo '这里是子类',PHP_EOL;
}
public function say(){
parent::say();
echo $this->name,"\t is \t",$this->gender,",and is \t ",$this->age,PHP_EOL;
}
public function cry(){
echo parent::$money,PHP_EOL;
echo '% >_< %',PHP_EOL;
echo self::$money,PHP_EOL;
echo "(*^_^*)";
}
}
$poor = new family();
$poor->name = 'Lee';
$poor->gender = 'female';
$poor->age = 25;
$poor->say();
$poor->cry();
```
返回结果:
```
这里是父类
这里是子类
Lee is female
Lee is female,and is 25
10000
% >_< %
1000
(*^_^*)%
```
在继承中,用parent指代父类,用self指代自己。
用“::”运算符调用父类方法,“::”操作符还用来作为类常量和静态方法的调用,不要把这两种应用混淆。
组合和继承都是提高代码可重用性的手段。在设计对象模型时,可以按照语义识别类之间的组合关系和继承关系。比如,继承是一种“是、像”的关系,而组合是一种“需要”的关系。利用这条规律,就可以很简单地判断出父亲与儿子应该是继承关系,父亲与家庭应该是组合关系。还可以从另一个角度看,组合偏重整体与局部的关系,而继承偏重父与子的关系。
从方法复用角度考虑,如果两个类具有很多相同的代码和方法,可以从这两个类中抽象出一个父类,提供公共方法,然后两个类作为子类,提供个性方法。这是用继承语意更好。
![](https://box.kancloud.cn/2016-03-16_56e93de63615a.png)
组合就没有这么多限制。组合之间的类可以关系很小,甚至没有关系
![](https://box.kancloud.cn/2016-03-16_56e93de6502f8.png)
在实际编程中,继承与组合的取舍往往并不是这么直接明了,很难说出二者是“像”的关系还是“需要”的关系,那么我们就要按照低耦合的标准来决定是继承还是组合。
耦合是一个软件结构内不同模块之间互连程序的度量,也就是不同模块之间的依赖关系。
低耦合指模块与模块之间,尽可能地使模块间独立存在;模块与模块之间的接口尽量少而简单。
解耦是要解除模块与模块之间的依赖。
如果这样子还没有办法区分两者,那么倾向于组合。
继承存在以下问题:
- 1.继承破坏封装性。
定义鸟类为父类,具有羽毛属性和飞翔方法,其子类天鹅、鸭子、鸵鸟等继承鸟这个类。但是鸵鸟不需要飞翔的方法,但作为子类,他却可以使用飞翔这个方法,显然破坏了类的封装性。
- 2.继承是紧耦合的。
继承使得子类和父类捆绑在一起。组合仅通过唯一接口和外部进行通信,耦合度低于继承。
- 3.继承扩展复杂
随着继承层数的增加和自类的增加,将涉及大量方法重写,使用组合,可以根据类型约束,实现动态组合,减少代码。
- 4.不恰当地使用继承可能违反现实世界中的逻辑
比如,人作为父类
组合也有缺点,在创建组合对象时,组合需要一一创建局部对象,这一定程度上增加了一些代码,而继承则不需要这一步,因为子类自动有了父类的方法。
```
<?php
/**
* User: 三千
* Date: 16/3/16
* Time: 下午6:57
*/
class car{
public function addoil(){
echo "Add oil \r\n";
}
}
class bmw extends car{
}
class benz{
public $car;
public function __construct(){
$this->car = new car();
}
public function addoil(){
$this->car->addoil();
}
}
$bmw = new bmw();
$bmw->addoil();
$benz = new benz();
$benz->addoil();
```
上面代码很显然,组合比继承增加了代码量。不过总体来说,优点大于缺点。
继承最大的优点就是扩展简单,但是其缺点大于优点,所以在设计时,需要慎重考虑。
使用继承的经验:
- 精心设计专门用于被继承的类,继承树的抽象层应该比较稳定,一般不要多余三层
- 对于不是专门用于被继承的类,禁止其被继承,也就是使用final修饰符。使用final修饰符即可防止重要方法被非法覆写,又能给编辑器寻找优化的机会
- 优先考虑用组合关系提高代码的可重用性
- 子类是一种特殊的类型,而不只是父类的一个角色
- 子类扩展,而不是覆盖或者使父类的功能失效
- 底层代码多用组合,顶层/业务层代码多用继承。底层用组合可以提高效率,避免对象臃肿。顶层代码用继承可以提高灵活性,让业务使用更方便。
- 空白目录
- 第1章 面向对象思想的核心概念
- 1.1 面向对象的“形”与“本”
- 1.1.1 对象的“形”
- 1.1.2 对象的“本质”
- 1.1.3 对象与数组
- 1.1.4 对象与类
- 1.2 魔术方法的应用
- 1.2.1 construct和destruct方法
- 1.2.2 set和get方法
- 1.2.3 call和callStatic方法
- 1.2.4 __toString方法
- 1.3 继承与多态
- 1.3.1 类的组合与继承
- 1.3.2 各种语言中的多态
- 1.4 面向接口编程
- 1.4.1 接口的作用
- 1.4.2 对接口的思考
- 1.5 反射
- 1.5.1 如何使用反射API
- 1.6 异常和错误处理
- 1.6.1 如何使用异常处理机制
- 1.6.2 怎样看PHP的异常
- 1.6.3 PHP中的错误级别
- 1.6.4 PHP中的错误处理机制
- 1.7 本章小结
- 第2章 面向对象的设计原则
- 2.1 面向对象设计的五大原则
- 2.2 一个面向对象留言本的实例
- 2.3 面向对象的思考
- 2.4 本章小结
- 第3章 正则表达式基础与应用
- 3.1 认识正则表达式
- 3.2 正则表达式中的元字符
- 3.3 正则表达式匹配规则
- 3.4 构造正则表达式
- 3.5 正则在实际开发中的应用
- 3.6 正则表达式的效率与优化
- 3.7 本章小结