1.單例設計模式
所謂單例模式,即在應用程序中最多隻有該類的一個實例存在,一旦創建,就會一直存在於內存中!
單例設計模式常應用於數據庫類設計,採用單例模式,只連接一次數據庫,防止打開多個數據庫連接。
一個單例類應具備以下特點:
單例類不能直接實例化創建,而是隻能由類本身實例化。因此,要獲得這樣的限制效果,構造函數必須標記爲private,從而防止類被實例化。
需要一個私有靜態成員變量來保存類實例和公開一個能訪問到實例的公開靜態方法。
在PHP中,爲了防止他人對單例類實例克隆,通常還爲其提供一個空的私有__clone()方法。
單例模式的例子:
<?php
/**
* Singleton of Database
*/
class Database
{
// We need a static private variable to store a Database instance.
privatestatic $instance;
// Mark as private to prevent it from being instanced.
private function__construct()
{
// Do nothing.
}
private function__clone()
{
// Do nothing.
}
public static function getInstance()
{
if (!(self::$instance instanceof self)) {
self::$instance = new self();
}
return self::$instance;
}
}
$a =Database::getInstance();
$b =Database::getInstance();
// true
var_dump($a === $b);
2.工廠設計模式
主要是當操作類的參數變化時,只用改相應的工廠類就可以
工廠設計模式常用於根據輸入參數的不同或者應用程序配置的不同來創建一種專門用來實例化並返回其對應的類的實例。
我們舉例子,假設矩形、圓都有同樣的一個方法,那麼我們用基類提供的API來創建實例時,通過傳參數來自動創建對應的類的實例,他們都有獲取周長和麪積的功能。
<?php
interface InterfaceShape
{
function getArea();
function getCircumference();
}
/**
* 矩形
*/
class Rectangle implements InterfaceShape
{
private $width;
private $height;
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
public function getArea()
{
return $this->width* $this->height;
}
public function getCircumference()
{
return 2 * $this->width + 2 * $this->height;
}
}
/**
* 圓形
*/
class Circle implements InterfaceShape
{
private $radius;
function __construct($radius)
{
$this->radius = $radius;
}
public function getArea()
{
return M_PI * pow($this->radius, 2);
}
public function getCircumference()
{
return 2 * M_PI * $this->radius;
}
}
/**
* 形狀工廠類
*/
class FactoryShape
{
public static function create()
{
switch (func_num_args()) {
case1:
return newCircle(func_get_arg(0));
case2:
return newRectangle(func_get_arg(0), func_get_arg(1));
default:
# code...
break;
}
}
}
$rect =FactoryShape::create(5, 5);
// object(Rectangle)#1 (2) { ["width":"Rectangle":private]=> int(5) ["height":"Rectangle":private]=> int(5) }
var_dump($rect);
echo "<br>";
// object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) }
$circle =FactoryShape::create(4);
var_dump($circle);
3.觀察者設計模式
觀察者模式是挺常見的一種設計模式,使用得當會給程序帶來非常大的便利,使用得不當,會給後來人一種難以維護的想法。
什麼是觀察者模式?一個對象通過提供方法允許另一個對象即觀察者 註冊自己)使本身變得可觀察。當可觀察的對象更改時,它會將消息發送到已註冊的觀察者。這些觀察者使用該信息執行的操作與可觀察的對象無關。結果是對象可以相互對話,而不必瞭解原因。觀察者模式是一種事件系統,意味着這一模式允許某個類觀察另一個類的狀態,當被觀察的類狀態發生改變的時候,觀察類可以收到通知並且做出相應的動作;觀察者模式爲您提供了避免組件之間緊密耦。看下面例子你就明白了!
<?php
/*
觀察者接口
*/
interface InterfaceObserver
{
function onListen($sender, $args);
function getObserverName();
}
// 可被觀察者接口
interface InterfaceObservable
{
function addObserver($observer);
function removeObserver($observer_name);
}
// 觀察者抽象類
abstract class Observer implements InterfaceObserver
{
protected $observer_name;
function getObserverName()
{
return $this->observer_name;
}
function onListen($sender, $args)
{
}
}
// 可被觀察類
abstract class Observable implements InterfaceObservable
{
protected $observers = array();
public function addObserver($observer)
{
if ($observer instanceof InterfaceObserver)
{
$this->observers[] = $observer;
}
}
public function removeObserver($observer_name)
{
foreach ($this->observersas $index => $observer)
{
if ($observer->getObserverName() === $observer_name)
{
array_splice($this->observers, $index, 1);
return;
}
}
}
}
// 模擬一個可以被觀察的類
class A extends Observable
{
public function addListener($listener)
{
foreach ($this->observers as $observer)
{
$observer->onListen($this, $listener);
}
}
}
// 模擬一個觀察者類
class B extends Observer
{
protected $observer_name = 'B';
public function onListen($sender, $args)
{
var_dump($sender);
echo "<br>";
var_dump($args);
echo "<br>";
}
}
// 模擬另外一個觀察者類
class C extends Observer
{
protected $observer_name = 'C';
public function onListen($sender, $args)
{
var_dump($sender);
echo "<br>";
var_dump($args);
echo "<br>";
}
}
$a = new A();
// 注入觀察者
$a->addObserver(new B());
$a->addObserver(new C());
// 可以看到觀察到的信息
$a->addListener('D');
// 移除觀察者
$a->removeObserver('B');
// 打印的信息:
// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
// string(1) "D"
// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
// string(1) "D"
4.適配器模式
將一個類的接口轉換成客戶希望的另一個接口,適配器模式使得原本的由於接口不兼容而不能一起工作的那些類可以一起工作。
應用場景:老代碼接口不適應新的接口需求,或者代碼很多很亂不便於繼續修改,或者使用第三方類庫。例如:php連接數據庫的方法:mysql,mysqli,pdo,可以用適配器統一
//老的代碼
class User {
private $name;
function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
//新代碼,開放平臺標準接口
interface UserInterface {
function getUserName();
}
class UserInfo implements UserInterface {
protected $user;
function __construct($user) {
$this->user = $user;
}
public function getUserName() {
return $this->user->getName();
}
}
$olduser = new User('張三');
echo $olduser->getName()."n";
$newuser = new UserInfo($olduser);
echo $newuser->getUserName()."n";
5.策略模式
將一組特定的行爲和算法封裝成類,以適應某些特定的上下文環境。
例如:一個電商網站系統,針對男性女性用戶要各自跳轉到不同的商品類目,並且所有廣告位展示不同的廣告
MaleUserStrategy.php
<?php
namespace IMooc;
class MaleUserStrategy implements UserStrategy {
function showAd()
{
echo "IPhone6";
}
function showCategory()
{
echo "電子產品";
}
}
FemaleUserStrategy.php
<?php
namespace IMooc;
class FemaleUserStrategy implements UserStrategy {
function showAd()
{
echo "2014新款女裝";
}
function showCategory()
{
echo "女裝";
}
}
UserStrategy.php
<?php
namespace IMooc;
interface UserStrategy {
function showAd();
function showCategory();
}
<?php
interface FlyBehavior{
public function fly();
}
class FlyWithWings implements FlyBehavior{
public function fly(){
echo "Fly With Wings \n";
}
}
class FlyWithNo implements FlyBehavior{
public function fly(){
echo "Fly With No Wings \n";
}
}
class Duck{
private $_flyBehavior;
public function performFly(){
$this->_flyBehavior->fly();
}
public function setFlyBehavior(FlyBehavior $behavior){
$this->_flyBehavior = $behavior;
}
}
class RubberDuck extends Duck{
}
// Test Case
$duck = new RubberDuck();
/* 想讓鴨子用翅膀飛行 */
$duck->setFlyBehavior(new FlyWithWings());
$duck->performFly();
/* 想讓鴨子不用翅膀飛行 */
$duck->setFlyBehavior(new FlyWithNo());
$duck->performFly();
6.裝飾器模式
使用場景:當某一功能或方法draw,要滿足不同的功能需求時,可以使用裝飾器模式;實現方式:在方法的類中建addDecorator(添加裝飾器),beforeDraw,afterDraw 3個新方法, 後2個分別放置在要修改的方法draw首尾.然後創建不同的裝器類(其中要包含相同的,beforeDraw,afterDraw方法)能過addDecorator添加進去,然後在beforeDraw,afterDraw中循環處理,與觀察者模式使用有點相似
1.裝飾器模式(Decorator),可以動態地添加修改類的功能
2.一個類提供了一項功能,如果要在修改並添加額外的功能,傳統的編程模式,需要寫一個子類繼承它,並重新實現類的方法
3.使用裝飾器模式,僅需在運行時添加一個裝飾器對象即可實現,可以實現最大的靈活性
DrawDecorator.php
<?php
namespace IMooc;
interface DrawDecorator
{
function beforeDraw();
function afterDraw();
}
Canvas.php
<?php
namespace IMooc;
class Canvas
{
public $data;
protected $decorators = array();
//Decorator
function init($width = 20, $height = 10)
{
$data = array();
for($i = 0; $i < $height; $i++)
{
for($j = 0; $j < $width; $j++)
{
$data[$i][$j] = '*';
}
}
$this->data = $data;
}
function addDecorator(DrawDecorator $decorator)
{
$this->decorators[] = $decorator;
}
function beforeDraw()
{
foreach($this->decorators as $decorator)
{
$decorator->beforeDraw();
}
}
function afterDraw()
{
$decorators = array_reverse($this->decorators);
foreach($decorators as $decorator)
{
$decorator->afterDraw();
}
}
function draw()
{
$this->beforeDraw();
foreach($this->data as $line)
{
foreach($line as $char)
{
echo $char;
}
echo "<br />\n";
}
$this->afterDraw();
}
function rect($a1, $a2, $b1, $b2)
{
foreach($this->data as $k1 => $line)
{
if ($k1 < $a1 or $k1 > $a2) continue;
foreach($line as $k2 => $char)
{
if ($k2 < $b1 or $k2 > $b2) continue;
$this->data[$k1][$k2] = ' ';
}
}
}
}
ColorDrawDecorator.php
<?php
namespace IMooc;
class ColorDrawDecorator implements DrawDecorator
{
protected $color;
function __construct($color = 'red')
{
$this->color = $color;
}
function beforeDraw()
{
echo "<div style='color: {$this->color};'>";
}
function afterDraw()
{
echo "</div>";
}
}
index.php
<?php
define('BASEDIR', __DIR__);
include BASEDIR.'/IMooc/Loader.php';
spl_autoload_register('\\IMooc\\Loader::autoload');
$canvas = new IMooc\Canvas();
$canvas->init();
$canvas->addDecorator(new \IMooc\ColorDrawDecorator('green'));
$canvas->rect(3,6,4,12);
$canvas->draw();