为什么使用OOP
OOP是一个模块化的过程,目的是为了把复杂问题简单化,一个模块解决一个复杂问题的某一个方面,即一个类应当只有一个职责
-
OOP区别于顺序式编程与过程式编程,在于:
1.顺序编程:用于处理最简单的问题 2.过程编程:将代码分为模块以便在程序中重用,程序猿输为一个函数 输入不同实参就能利用不同具体值使用函数 3.OOP:形同过程编程,长处在于能处理自己的数据结构,更方便地处理 独立但相互关联的类
从外部源启动PHP类,往往由其它模块调动,不会自启动,举个反例:
<?php
class TellAll{
private function __construct(){
...
}
}
$tellAll = new TellAll();
?>
OOP基本概念
抽象(abstract)
用于指示一个对象的基本特征,是处理复杂性的具体方法。
我们会对现实中的相似性分组,对具体的相似性抽象。
举个例子:我们一般不会叫自己的爱宠哈士奇为"我的蠢萌蠢萌的、摇着尾巴的、爱捣乱的名叫Jeff的哈士奇",而往往会直接说:"我的狗!"
抽象类不能实例化,只能由具体类(可以实例化的类,非抽象类)继承抽象类的接口以及所有具体属性
所有类都是对数据的一组操作的抽象
基本语法:
<?php
//IAbstract.php
abstract class IAbstract{
public $storeHere; //可以定义属性
public function test(){
...//非抽象类,继承子类无须实现
}
abstract public function trick($whatever);
//作为对继承子类的限制
}
?>
<?php
//OneAbstract.php
class OneAbstract extends IAbstract{
public function trick(){
...//声明了抽象方法就必须实现
}
}
?>
接口(interface)
不能像抽象类那样在接口中包含具体方法或变量,除非是具有抽象性的接口,可以包含具体常量
接口的核心部分由类中操作(函数)定义的所有签名组成。签名包括一个操作的操作名和参数,一个接口表示的就是所有签名的集合。例如以下代码,签名由trick()和形参$whatever组成
public function trick($whatever){
echo 'signature';
}
如果要实现接口(implements),就要保证实现接口中的所有方法,在此基础上可以再继续添加额外的方法
<?php
//ImethodHolder.php
interface IMethodHolder{
public function getInfo($info);
public function sendInfo($Info);
public function calculate($first,$second);
}
?>
<?php
//ImplementAlpha.php
include_once('IMethodHolder.php');
class ImplementAlpha implements IMethodHolder{
/******** 接口中所有方法必须实现 ********/
public function getInfo($info){
echo 'This is my News!' . $info."<br/>";
}
public function sendInfo(){
return $Info;
}
public function calculate($first,$second){
$calculate = $first * $second;
return $calculate;
}
/******** 除此之外可以增加其他类 ********/
public function useMethods(){
$this->getInfo('习近平会见马英九');
echo $this->sendInfo('恒大战平阿赫利') . "<br/>";
echo "Salary : $" . $this->calculate(20,15) ;
}
$worker = new ImplementAlpha;
$worker->useMethods();
//前面提到不要自启动,这里为了方便就直接自启动实例化类
//不过可以看到,在实现类中,方法都是经过useMethods的方法调用的
//在后面章你会看到很多例子都是这样实现的,而往往不会直接调用
}
?>
OOP和设计模式有很多重要的结构要素,其中之一就是指定数据类型为接口而不是一个具体实现,对数据的引用要通过父类完成。如下所示:
<?php
//IProduct.php
interface IProduct{
function apples();
function books();
}
?>
<?php
//FruitStore.php
include_once('IProduct.php');
class FruitStore store implements IProduct{
public function apples(){
return 'Fruit shop-----We have apples';
}
public function books(){
return 'Fruit shop-----We don't have books';
}
}
?>
<?php
//BookStore.php
//再来一个BookStore类同上,No apples,but books
?>
<?
//useProduct.php
//两个实现include进来,此处省略代码
class useProduct{
public function __construct(){
$apple = new FruitStore();
$book = new BookStore();
$this->doInterface($apple);
$this->doInterface($book);
//实例化类在一个方法中,调用类的方法又在另一个方法中,降低了耦合度
}
function doInterface(IProduct $product){
echo $product->apples();
echo $product->books();
}
}
$worker = new useProduct();
?>
这就是强制数据类型,其中使用的对象(类)必然有给定的接口,如果把一个接口 (一个对象类或者接口) 作为代码提示,绑定会更宽松)它会绑定到接口而不是绑定到一个特定的实现,如上面的doInterface(IProduct $product)
封装(Encapsulation)
封装是画份一个抽象的诸多元素的过程,这些元素构成该抽象的结构和行为,封装的作用就是将抽象的契约接口与其实现分离
通过3种类型的可见性保护封装(private/protected/public)。但是一个类还是要有可见方法访问封装,比如__consruct构造函数,默认为公共的
为了保持封装而又提供可访问性,OOP建议使用getter()和setter()方法,但是不能滥用,否则会破坏封装
<?php
class GetSet{
private $data;
function __construct(){
$this->setter(200);
$got = $this->getter();
echo $got;
}
private function getter(){
return $this->data;
}
private function setter($setValue){
$this->data = $setValue;
}
}
$worker = new GetSet();
?>
继承(extends)
假设我有一只哈士奇(我们称之为子类),那么它继承了狗(父类)的属性,比如四只脚,看到的世界都是通过#404040层过滤的。而哈士奇区别于普通狗,又有新的特征:逗比,爱捣乱
为了保证类之间的松绑定,通常会继承抽象类,而且是浅继承(只有一层子类)。深继承的话,一旦对父类进行简单修改,子类会带来严重的破坏
<?php
//dog.php
class dog{
protected $pet;
//共同特征,四条腿
protected function fourlegs(){
return 'walk on all four';
}
//宠物性格
protected function character($petChar){
$this->$pet = $petChar;
}
}
?>
<?php
//haski.php
include_once 'dog.php';
class haski extends dog{
function __construct(){
echo 'Haski ' . $this->fourlegs() . "<br/>";
echo $this->character('They are crazy!') . "<br/>";
echo $this->naughty() . "<br/>";
}
private function naughty(){
return 'Haski dogs are naughty';
}
}
?>
<?php
//client.php
include_once 'haski.php';
class client{
function __construct(){
$haski = new haski();
}
}
$worker = new Client();
?>
多态(polymorphism)
多态的真正价值在于可以调用有相同接口的对象来完成不同的工作。一个大型项目中,增加和修改会对程序带来巨大影响,除非有一个公共的接口(父类或接口),例如:
<?php
//Poly.php
interface ISpeed{
function fast();
function cruise();
function slow();
}
class Jet implements ISpeed{
function slow(){
return 120;
}
function cruise(){
return 1200;
}
function fase(){
return 1500;
}
}
class car implements ISpeed{
function slow(){
$carslow = 15;
return $carslow;
}
function cruise(){
$carcruise = 65;
return $carcruise;
}
function fase(){
$carZoom = 110;
return $carZoom;
}
}
$f22 = new Jet();
//各种调用,省略
$ford = new Car();
//同上
?>
从上面的例子看出,Jet和Car类对接口的实现有很大不同。但是基于这样一个公共接口,在一个给定的程序结构中做出修改或者增补时,可以放心地请求或使用接口方法,而不必担心程序会崩溃
抽象还是接口
(引用于CSDN-PHP的抽象类、接口的区别)
如果要创建一个模型,这个模型将由一些紧密相关的对象采用,就可以使用抽象类。如果要创建将由一些不相关对象采用的功能,就使用接口。
如果必须从多个来源继承行为,就使用接口。
如果知道所有类都会共享一个公共的行为实现,就使用抽象类,并在其中实现该行为。
PS:该篇引用于《Learning PHP设计模式》第1、2章节
Chap2 预告 :设计模式与UML
算法处理操作速度,设计模式解决开发速度