Zihao

Make small but daily progress

0%

面向对象的基础三

面向对象之封装

每个对象都包含它能进行操作所需要的所有信息,这个特性称为封装,因此对象不必依赖其他对象来完成自己的操作。这样方法和属性包装在类中,通过类的实例来实现。

封装的好处:

  1. 良好的封装能够减少耦合(耦合的意思就是两个单元之间紧密配合与相互影响)。

  2. 类内部的实现可以自由地修改。

  3. 类具有清晰的对外接口。

解释封装的意思就是将单独的单元或者称之为模块写成一个方法,便于调用。此方法只负责单一的功能。

面向对象之继承

继承理解起来也很容易,工作方式就是定义子类和父类,或叫做基类和派生类,其种子类继承父类的所有特性,子类不但继承了父类的特性,还可以定义新的特性,还可以以自己的方式实现父类的功能(方法重写)。如果需要调用父类的构造函数,则可以使用:parent::父类函数 或 父类名::父类函数。默认情况下会自动调用父类的构造方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

class Fruit {

public function __construct($name){

echo ‘水果’.$name.’创建了’;

}

}

class Apple extends Fruit {

public function __construct($name){

parent::__construct($name);

}

}

$apple = new Apple(“苹果”);

// 输出 水果苹果创建了

?>

继承是有缺点的,就是父类变化,子类不得不变,继承会破坏包装,父类实现细节暴漏给子类,这样就增加了两大类之间的耦合性(藕断丝连,尽管两个类分开,但如果关系密切,一方的改变就会影响另一方,就是耦合性高的表现)。

面向对象之多态

多态去理解的话就是不同的对象可以执行相同的动作,但要通过他们自己的实现代码来执行。多态的原理只有对象继承最末端的方法实现会被调用。

多态这个概念,在Java中指的是变量可以指向的对象的类型,可是变量声明类型的子类。对象一旦创建,它的类型是不变的,多态的是变量。

在PHP5中,变量的类型是不确定的,一个变量可以指向任何类型的数值、字符串、对象、资源等。我们无法说PHP5中多态的是变量。

我们只能说在PHP5中,多态应用在方法参数的类型提示位置。

一个类的任何子类对象都可以满足以当前类型作为类型提示的类型要求。所有实现这个接口的类,都可以满足以接口类型作为类型提示的方法参数要求。简单的说,一个类拥有其父类、和已实现接口的身份。

通过实现接口实现多态

下面的例子中,UserAdmin类的静态方法,要求一个User类型的参数。

在后面的使用中,传递了一个实现了User接口的类NormalUser的实例。代码成功运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?

interface User{ // User接口

public function getName();

public function setName($_name);

}

class NormalUser implements User { // 实现接口的类.
private $name;
public function getName(){
return $this->name;
}
public function setName($_name){
$this->name = $_name;
}
}
class UserAdmin{ //操作.
public static function ChangeUserName(User $_user,$_userName){
$_user->setName($_userName);
}
}
$normalUser = new NormalUser();
UserAdmin::ChangeUserName($normalUser,"Tom");//这里传入的是 NormalUser的实例.
echo $normalUser->getName();
?>

程序运行结果:

1
tom

通过继承关系实现多态

下面是类和子类的关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?

classUser{ // User接口

public function getName(){}

}

classNormalUser extendsUser { // 继承自User类

private $name;

public function getName(){
return $this->name;
}
public function setName($_name){
$this->name = $_name;
}
}
class UserAdmin{ //操作.
public static function ChangeUserName(User $_user,$_userName){
$_user->setName($_userName);
}
}
$normalUser= newNormalUser();
UserAdmin::ChangeUserName($normalUser,"Tom");//这里传入的是 NormalUser的实例.
echo$normalUser->getName();
?>

程序运行结果:

1
Tom

小结

  1. 当一个父类知道所有的子类都有一个方法,但是父类不能确定该方法如何写,可以让子类去覆盖它的方法,方法覆盖(重写),必须要求子类的方法名和参数个数完全一致
  2. 如果子类要去调用父类的某个方法(protected/public),可以使用 父类名::方法名 或者 parent::方法名
  3. 在实现方法重写的时候,访问修饰符可以不一样,但是子类方法的访问权限必须大于等于父类方法的访问权限(即不能缩小父类方法的访问权限)。如:
    1. 父类public function cry(){} 子类 protected function cry(){} 则会报错但是子类的访问权限可以放大。
    2. 父类private function cry(){} 子类 protected function cry(){} 可以正确执行。

欢迎关注我的其它发布渠道