PHP設計模式(六):MVC

原文地址:PHP設計模式(六):MVCphp

Introduction

20世紀80年代,計算機發展迅速,編程技術也日益分化。桌面應用編程,也逐漸出現了用戶圖形界面和程序邏輯分離的程序設計。到了90年代,web的出現更是讓這種程序設計模式得以延續。
這種設計模式即是MVC(Model-View-Control),除了MVC,還有MVC的變種,如MVVM(Model-View-View Model)等。程序員

MVC

回到80年代的桌面應用編程,當時面向對象的編程設計模式(見PHP設計模式(一):基礎編程模式)興起,程序員將桌面應用分割成兩個大的對象:領域對象(domain objects)和可視對象(presentation objects)。領域對象是對現實事物的抽象模型,可視對象是對用戶界面部分的抽象模型。
後來人們發現,只有領域對象和可視對象是不夠的,特別是在複雜的業務中。根據PHP設計模式(三):封裝中介紹的設計原則,在面向對象程序設計中,類和類之間的訪問、交互和更新應該是經過Accessors和Mutators。
那麼若是操做領域對象呢?人們引入了控制器(controller)的對象,經過控制器來操做領域模型。
到此,MVC模型逐漸穩定下來,用戶經過可視對象操做控制器對象,控制器對象再去操做領域對象。web

MVC中的設計模式

上面介紹的MVC屬於抽象度比較高的設計模式,在實際編程中,須要遵照下面的設計模式。編程

基於接口去編程

基於接口去編程的好處就是分離設計和實現,這一點咱們在PHP設計模式(二):抽象類和接口已經介紹過了,下面咱們舉一個實際的例子來講明這個設計的好處。設計模式

<?php
abstract class Animal {
  protected $name;
  abstract protected function eatFish();
  abstract protected function eatMoss();
  public function eat() {
    if ($this->eatFish()) {
      echo $this->name . " can eat fish.\n";
    }
    if ($this->eatMoss()) {
      echo $this->name . " can eat moss.\n";
    }
  }
}
?>

咱們建立一個鯨魚類:架構

<?php
include_once('Animal.php');
class Whale extends Animal {
  public function __construct() {
    $this->name = "Whale";
  }
  public function eatFish() {
    return TRUE;
  }
  public function eatMoss() {
    return FALSE;
  }
}

$whale = new Whale();
$whale->eat();
?>

運行一下:dom

$ php Whale.php
Whale eats fish.

看上去沒什麼問題,對吧?咱們建立一個鯉魚類:this

<?php
include_once('Animal.php');
class Carp extends Animal {
  public function __construct() {
    $this->name = "Carp";
  }
  public function eatMoss() {
    return TRUE;
  }
}

$carp = new Carp();
$carp->eat();
?>

運行一下:架構設計

$ php Carp.php
PHP Fatal error: Class Carp contains 1 abstract method and must therefore be
declared abstract or implement the remaining method (Animal::eatFish) in
Carp.php on line 9

報錯了,對吧?由於咱們實現Carp.php的時候故意沒有去實現eatFish接口,基於接口的編程設計模式能夠在開發期就發現這種邏輯錯誤。設計

使用組件而不是繼承

將一個對象拆成更小的對象,這些小的對象成爲組件(composition)。儘可能使用組件而不是繼承的設計模式的意義在於,多種繼承之下,子類可能會擁有大量毫無心義的未實現方法。而經過組件的方式,子類能夠選擇須要的組件。
下面給出一個例子:

<?php
abstract class Animal {
  protected $name;
  abstract protected function eatFish();
  abstract protected function eatMoss();
  public function eat() {
    if ($this->eatFish()) {
      echo $this->name . " can eat fish.\n";
    }
    if ($this->eatMoss()) {
      echo $this->name . " can eat moss.\n";
    }
  }
}

class Whale extends Animal {
  protected function __construct() {
    $this->name = "Whale";
  }
  protected function eatFish() {
    return TRUE;
  }
  protected function eatMoss() {
    return FALSE;
  }
}

class BullWhale extends Whale {
  public function __construct() {
    $this->name = "Bull Whale";
  }
  public function getGender() {
    return "Male";
  }
}
?>

這裏的BullWhale其實很是冗餘,實際的業務模型可能並不須要這麼複雜,這就是多重繼承的惡果。
而組件則不一樣,經過將行爲拆分紅不一樣的部分,又最終子類決定使用哪些組件。
下面給出一個例子:

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

class Gender {
  private $gender;
  public function __construct($gender) {
    $this->gender= $gender;
  }
  public function getGender() {
    return $this->gender;
  }
}

class BullWhale {
  private $action;
  private $gender;
  public function __construct() {
    $this->action = new Action("Bull Whale");
    $this->gender = new Gender("Male");
  }
  public function eatFood($food) {
    $this->action->eat($food);
  }
  public function getGender() {
    return $this->gender->getGender();
  }
}

$bullWhale = new BullWhale();
$bullWhale->eatFood("fish");
echo $bullWhale->getGender() . "\n";
?>

運行一下:

$ php BullWhale.php
Bill Whale eat fish.
Male

BullWhale由Action和Gender組件構成,不一樣的類能夠選擇不一樣的組件組合,這樣就不會形成類冗餘了。

Summary

實際編程中,更多的每每是混合架構,如既包含繼承,又包含組件的編程設計模式。不過,掌握基本的編程架構設計是一切的基礎。

相關文章
相關標籤/搜索