PHP設計模式(三):封裝

原文地址:PHP設計模式(三):封裝php

Introduction

面向對象編程中,一切都是對象,對一個對象的封裝,也成了面向對象編程中必不可少的部分。
和C/C++,Java,Python等語言同樣,PHP也支持封裝。程序員

封裝/Encapsulation

對事物的封裝是指,將事物進行抽象後,提供抽象概念的實現的具體方法。編程

聽起來很拗口,仍是舉鯨魚的例子。
對於鯨魚來講,須要吃東西這個行爲,吃自己是一個抽象的概念,由於具體到怎麼吃,是咀嚼和消化的過程,甚至如何咀嚼和消化也是不可見的。對外部而言,可見的只是吃這一個接口,如何吃、怎麼吃,是被封裝在了鯨魚的實現中。
甚至能夠說,消化系統,被封裝到了鯨魚這個對象中,對外部不可見,僅僅鯨魚本身可見。設計模式

封裝方法

和別的程序設計語言同樣,PHP也只是三種封裝概念:Private,Protected,Public。this

私有/Private

私有的概念是,僅僅對象內部可見,外部不可見,如:設計

<?php
class Whale {
  private $name;
  public function __construct() {
    $this->name = "Whale";
  }
  public function eat($food) {
    chew($food);
    digest($food);
  }
  private function chew($food) {
    echo "Chewing " . $food . "\n";
  }
  private function digest($food) {
    echo "Digest " . $food . "\n";
  }
}
?>

name是鯨魚的私有屬性,chew()和digest()是鯨魚的私有方法,對於其餘類來講,都是不可見的。對於現實來講,咱們若是隻是注重吃,並無必要去關心鯨魚是如何去吃的。code

保護/Protected

保護的概念是,僅僅是自身類和繼承類可見,這個關鍵字的用途主要是防止濫用類的派生,另外三方庫編寫的時候會用到,防止誤用。對象

<?php
abstract class Animal {
  private $name;
  abstract public function eat($food);
  protected function chew($food) {
    echo "Chewing " . $food . "\n";
  }
  protected function digest($food) {
    echo "Digest " . $food . "\n";
  }
}

class Whale extends Animal {
  private $name;
  public function __construct() {
    $this->name = "Whale";
  }
  public function eat($food) {
    chew($food);
    digest($food);
  }
}
?>

鯨魚類能夠經過繼承使用動物類的咀嚼和消化方法,可是別的繼承鯨魚類的類就不能夠再使用動物類的咀嚼和消化方法了。保護更可能是用於面向對象設計,而不是爲了編程來實現某個需求。繼承

公共/Public

公共的概念就是,任何類、任何事物均可以訪問,沒有任何限制,這裏再也不贅述。接口

Getters/Setters

Getters和Setters也叫Accessors和Mutators,在Java/C#等語言中常以get()/set()方法出現。
對於這兩個東西的爭議很大,考慮下面一個類:

<?php
class Price {
  public $priceA;
  public $priceB;
  public $priceC;
  ...
}
?>

若是不使用Getters/Setters,咱們給Price類賦值和取值通常是這樣:

<?php
  $price = new Price();
  $price->priceA = 1;
  $price->priceB = 2;
  $price->priceC = 3;
  ...
  echo $price->priceA;
  echo $price->priceB;
  echo $price->priceC;
  ...
?>

可是若是使用了Getters/Setters,Price類將變成這樣:

<?php
class Price {
  private $priceA;
  private $priceB;
  private $priceC;
  public function getPriceA() {
    return $this->priceA;
  }
  public function setPriceA($price) {
    $this->priceA = $price;
  }
  ...
}
?>

這時候賦值將變成這樣:

<?php
  $price = new Price();
  $price->setpriceA(1);
  $price->setPriceB(2);
  $price->setPriceC(3);
  ...
  echo $price->getPriceA();
  echo $price->getPriceB();
  echo $price->getPriceC();
  ...
?>

是否是感受須要多敲不少代碼?這也是不少程序員不肯意使用get/set的緣由,形成了大量的看似無用冗餘的代碼。
爲何叫看似冗餘和無用?由於Getters/Setters是編程設計方法,而不是編程實現方法。

在面向對象程序設計中,類和類之間的訪問、交互和更新應該是經過Accessors和Mutators,也就是Getters和Setters來實現。直接訪問和修改破壞了類的封裝性。

爲何採用這種設計方式?由於程序設計是對現實問題的抽象,而在編程的工程中程序員扮演的角色每每是上帝。
考慮這樣一種場景:你朋友要求你更名,決定是否更名的人是你,而不是你朋友。在你的朋友的視覺(也就是你朋友的類),他不能直接去修改你的名字。
若是你直接採用非Getters/Setters的設計方法,事實上是程序員扮演的這個上帝修改了現實規則,容許你朋友可以隨意更改你的姓名,顯然這是不合理的。

Summary

合理的封裝對於好的程序設計是必不可少的,雖然什麼都是Public也能解決編程問題,可是這不是用程序設計解決問題的思路。

相關文章
相關標籤/搜索