什麼是封裝?php
把客觀的事物封裝成抽象的類,而且類能夠把本身的數據和方法只讓可信的類或者對象操做,對不可信的類進行信息的隱藏。簡單的說就是:封裝使對象的設計者與對象的使用者分開,使用者只要知道對象能夠作什麼就能夠了,不須要知道具體是怎麼實現的。封裝能夠有助於提升類和系統的安全性。編程
什麼是繼承?設計模式
繼承指的是創建一個新的派生類,從一個或多個先前定義的類中繼承數據和函數,能夠從新定義或加進新數據和函數,從而創建了類的層次或等級。安全
什麼是多態?函數
多態性指的是: 同一操做做用與不一樣類的實例,將產生不一樣的執行結果,即不一樣類的對象收到相同的消息時,將獲得不一樣的結果。字體
class eat {
public function breakfast() {
echo "吃早飯!";
}
}
class typist {
public function type() {
echo "打字!";
}
}
function printWorking($obj) {
if ($obj instanceof eat) {
echo $obj->breakfast();
} elseif ($obj instanceof typist) {
echo $obj->type();
} else {
echo "error";
}
}
printWorking(new eat());
echo PHP_EOL;
printWorking(new typist());
複製代碼
輸出:this
吃早飯! 打字!編碼
單一職責原則,開放封閉原則,里氏替換原則,依賴倒置原則,接口隔離原則spa
什麼是單一職責原則?設計
簡單的來講就是: 一個類只作一件事情,不要爲類實現過多的功能點,避免相同的職責分散到不一樣的類中。若是一個類的職責過多可能引發變化的緣由也就越多,使代碼更加的耦合。若是雜交不清的職責將使得代碼難以維護,牽一髮而動全身。
例如:工廠模式,工廠模式之因此被稱爲工廠模式是由於它負責 「生產」 對象。
工廠模式的好處:多個地方new了一個對象,當此類名發生改變就不須要一個個去修改,只須要修改一處地方。
<?php
class MyObject {
public function __construct() {
echo "test code";
}
}
//工廠類
class MyFactory {
public static function factory() {
return new MyObject();
}
}
$instance = MyFactory::factory();//test code
複製代碼
什麼是開放封閉原則?
開放封閉原則: 一個類是可擴展的,而不可修改的。也就是說,對擴展開放,對修改封閉。
1.對擴展開放,意味着 有新的需求或變化時,能夠對現有的代碼進行擴展,以適應新的狀況。
2.對修改封閉,在對模塊功能進行擴展時,不該該影響已有的程序模塊。
實現開放封閉的原則的重點:抽象編程,而不是具體編程,由於抽象相對穩定,讓類依賴與固定的抽象類和接口,因此修改就是封閉的。而面向對象的繼承和多態機制,又能夠繼承抽象類或者實現接口,聽太重寫其方法來改變固有的行爲,實現方法新的拓展,因此就是開放。
例如:裝飾器模式(Decorator),能夠動態地添加修改類的功能。一個類提供了一項功能,若是要在修改並添加額外的功能,傳統的編程模式,須要寫一個子類去繼承它,並從新實現類的方法,使用裝飾器模式,僅需在運行時添加一個裝飾器對象便可實現,能夠實現最大的靈活性。
<?php
/** * 輸出一個字符串 * 裝飾器動態添加功能 * Class EchoText */
class EchoText {
protected $decorator = [];
public function Index() {
//調用裝飾器前置操做
$this->beforeEcho();
echo "你好,我是裝飾器。";
//調用裝飾器後置操做
$this->afterEcho();
}
//增長裝飾器
public function addDecorator(Decorator $decorator) {
$this->decorator[] = $decorator;
}
//執行裝飾器前置操做 先進先出原則
protected function beforeEcho() {
foreach ($this->decorator as $decorator)
$decorator->before();
}
//執行裝飾器後置操做 先進後出原則
protected function afterEcho() {
$tmp = array_reverse($this->decorator);
foreach ($tmp as $decorator)
$decorator->after();
}
}
/** * 裝飾器接口 * Class Decorator */
interface Decorator {
public function before();
public function after();
}
/** * 顏色裝飾器實現 * Class ColorDecorator */
class ColorDecorator implements Decorator {
protected $color;
public function __construct($color) {
$this->color = $color;
}
public function before() {
echo "<dis style='color: {$this->color}'>";
}
public function after() {
echo "</div>";
}
}
/** * 字體大小裝飾器實現 * Class SizeDecorator */
class SizeDecorator implements Decorator {
protected $size;
public function __construct($size) {
$this->size = $size;
}
public function before() {
echo "<dis style='font-size: {$this->size}px'>";
}
public function after() {
echo "</div>";
}
}
//實例化輸出類
$echo = new EchoText();
//增長裝飾器
$echo->addDecorator(new ColorDecorator('red'));
//增長裝飾器
$echo->addDecorator(new SizeDecorator('22'));
//輸出
$echo->Index();
複製代碼
什麼是里氏替換原則?
因爲面向對象編程技術中的繼承在具體編程中過於簡單,在許多系統的設計和編程實現中,咱們並無認真地、理性地思考應用系統中各個類之間的繼承好關係是否合適,派生類是否能正確地對基類中的某些方法進行重寫的問題。所以常常出現濫用繼承或者錯誤的繼承現象,給系統後期的維護帶來了很多麻煩。
核心思想:子類必須可以替換其父類。這一思想體現爲對繼承機制的約束規範,只有子類可以替換父類時才能保證系統在運行期內識別子類,這是保證繼承複用的基礎。
<?php
//例子1
class Bird{
protect function fly(){
}
}
//翠鳥
class KingFisher extends Bird{
}
//鴕鳥
class Ostrich extends Bird{
//鴕鳥不會飛啊
}
//例子2
class A{
protect function add($a, $b){
return $a + $b;
}
}
//重載
class B extends A{
protected function add($a, $b){
return $a + $b + 100;
}
}
複製代碼
里氏替換原則是對類繼承的一種約束。對里氏替換原則有兩種理解:
1.不能隨便去繼承不合適的,有多餘方法或者屬性的類(例子1)。
2.子類能夠擴展父類的功能,但不能改變父類原有的功能(例子2)。
里氏替換原則包含一下幾個隱藏含義:
1.子類能夠實現父類的抽象方法,但不能覆蓋父類的非抽象方法。
2.子類中能夠增長本身特有的方法。
3.當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬鬆。
4.當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格。
什麼是依賴倒置原則?
簡單的來講就是:一個類,不該該強制依賴另外一個類,每一個類對於另一個類都是可替換的。
具體概念:
1.上層模塊不該該依賴於下層模塊,它們共同依賴於一個抽象(父類不能依賴子類,它們都要依賴抽象類)。
2.抽象不能依賴於具體,具體應該依賴於抽象。
爲何要依賴接口?由於接口體現對問題的抽象,同時因爲抽象通常是相對穩定的或者是相對變化不頻繁的,而具體是易變的。所以,依賴抽象是實現代碼擴展和運行期內綁定(多態)的基礎:只要實現了該抽象類的子類,均可以被類的使用者使用。
<?php
interface employee {
public function working();
}
class teacher implements employee//具體應該依賴與抽象 {
public function working(){
echo 'teaching...';
}
}
class coder implements employee {
public function working(){
echo 'coding...';
}
}
class workA//例子1 {
public function work(){
$teacher = new teacher;
$teacher->working();
}
}
class workB//例子2 {
private $e;
public function set(employee $e){
$this->e = $e;
}
public function work(){
$this->e->working();
}
}
$worka = new workA;//workA 依賴於 teacher 類 不符合依賴倒置原則
$worka->work();
$workb = new workB;//workB 不依賴與某個類 既能夠注入 teacher 也能夠 注入 coder
$workb->set(new teacher());
$workb->work();
複製代碼
在workA(例子1)中,work方法依賴於teacher實現;在workB(例子2)中,work轉而依賴抽象,這樣能夠把須要的對象經過參數傳入。上述代碼經過接口,實現了必定程度的解耦,但仍然是有限的。不只是使用接口,使用工廠等也能實現必定程度的解耦和依賴倒置。
在workB中,teacher實例經過set方法傳入,從而實現了工廠模式。因爲這樣的實現仍然是硬編碼的,爲了實現代碼的進一步擴展,把這個依賴關係寫在配置文件裏,指明workB須要一個teacher對象,專門由一個程序配置是否正確(如所依賴的類文件是否存在)以及加載配置中所依賴的實現,這個檢測程序,就稱爲IOC容器(這裏不清楚IOC的小夥伴能夠自行谷歌)。
什麼是接口隔離原則?
其核心思想是:使用多個小的專門的接口,而不要使用一個大的總接口(只須要關心接口,不須要關心實現)。
接口隔離原則體如今:
1.接口應該是內聚的,應該避免 「胖」 接口。
2.不要強迫依賴不用的方法,這是一種接口污染。
3.代表客戶端不該該被強迫實現一些不會使用的接口,應該把胖接口分組,用多個接口代替它,每一個接口服務於一個子模塊。簡單地說,就是使用多個專門的接口比使用單個接口要好不少。
隔離的手段主要有如下兩種: 一、委託分離,經過增長一個新的類型來委託客戶的請求,隔離客戶和接口的直接依賴,可是會增長系統的開銷(設計模式中,如:代理模式,策略模式中都用到了委託的概念,好奇的小夥伴能夠自行谷歌,這裏就不貼代碼了)。
二、多重繼承分離,經過接口多繼承來實現客戶的需求,這種方式是較好的。
胖接口的實例說明
<?php
interface Animal{
public function walk();
public function speak();
}
//實現狗的一個接口
class Dog implements Animal{
public function walk(){
echo "dogs can walk";
}
public function speak(){
echo "dogs can speak";
}
}
//ok,如今咱們想建立一個魚類,它會游泳,怎麼辦呢?
//咱們必需要修改接口,還會影響到dog類的實現,而fish也須要實現walk和speak方法,以下代碼所示:
interface Animal{
public function walk();
public function speak();
public function swim();
}
//修改後的Gog類
class Dog implements Animal{
public function walk(){
echo "dogs can walk";
}
public function speak(){
echo "dogs can speak";
}
public function swim(){
}
}
//魚類
class Fish implements Animal{
public function walk(){
}
public function speak(){
}
public function swim(){
echo "fish can swim";
}
}
複製代碼
這時Animal接口類就呈現出了」胖「接口的特徵了。所謂胖接口其實就是接口中定義了不是全部實現類都須要的方法,就像Animal接口類,有些動物是不會游泳的,有些動物是不會行走的,還有些動物是不會飛的。若是將這些方法都寫在一個Animal接口類中,那麼後期的擴展和維護簡直就是一場災難。
那麼,怎麼解決以上問題呢?
很簡單,接口細化便可,將Animal接口類拆分紅三個接口類,而後用多繼承分離接口就ok了。
<?php
interface animalCanSpeak{
public function speak();
}
interface AnimalCanSwim{
public function swim();
}
interface animalCanSpeak{
public function speak();
}
//定義好這幾個接口類以後,dog和fish的實現就容易多了
//狗類
class Dog implements animalCanSpeak,animalCanWalk{
public function walk(){
echo "dogs can walk";
}
public function speak(){
echo "dogs can speak";
}
}
//魚類
class Fish implements AnimalCanSwim{
public function swim(){
echo "fish can swim";
}
}
複製代碼
接口隔離原則(Interface Segregation Principle, ISP)的概念:使用多個專門的接口,而不使用單一的總接口,即客戶端不該該依賴那些它不須要的接口。
在使用接口隔離原則時,咱們須要注意控制接口的粒度,接口不能過小,若是過小會致使系統中接口氾濫,不利於維護;接口也不能太大,太大的接口將違背接口隔離原則,靈活性較差,使用起來很不方便。通常而言,接口中僅包含爲某一類用戶定製的方法便可,不該該強迫客戶依賴於那些它們不用的方法。
實踐出真理