這篇文章為大家帶來了關於PHP的相關知識,其中主要介紹了幾種常見的開發模式,下面一起來看一下,希望對大家有幫助。
設計模式六大原則
開放封閉原則:一個軟體實體如類別、模組和函數應該對擴充開放,對修改關閉。
里氏替換原則:所有引用基類的地方必須能透明地使用其子類的對象.
依賴倒置原則:高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽像不應該依賴細節;細節應該依賴抽象。
單一職責原則:不要存在多於一個導致類別變更的原因。通俗的說,即一個類只負責一項職責。
介面隔離原則:客戶端不應該依賴它不需要的介面;一個類別對另一個類別的依賴應該建立在最小的介面上。
迪米特法則:一個物件應該對其他物件保持最少的了解。
特點: 使用單例模式, 則可以避免大量的new 操作消耗的資源
單例類不能直接實例化創建,而是只能由類別本身實例化。因此,要獲得這樣的限制效果,建構函式必須標記為private,從而防止類別被實例化。
需要一個私人靜態成員變數來保存類別實例和公開一個能存取到實例的公開靜態方法。
在PHP中,為了防止他人對單例類別實例克隆,通常也為其提供一個空的私有__clone()方法。
$_instance必須宣告為靜態的私有變數
#建構子和析構函式必須宣告為私有,防止外部程式new 類別從而失去單例模式的意義
getInstance()方法必須設定為公有的,必須呼叫此方法以傳回實例的一個參考
::運算子只能存取靜態變數和靜態函數
new物件都會消耗記憶體
使用場景:最常用的地方是資料庫連接。
使用單例模式產生物件後, 該物件可以被其它眾多物件所使用。
私有的__clone()方法防止複製物件
<?php class Singleton{ //私有属性,用于保存实例 private static $instance; //构造方法私有化,防止外部创建实例 private function __construct(){}//公有方法,用于获取实例 public static function getInstance(){ //判断实例有无创建,没有的话创建实例并返回,有的话直接返回 if(!(self::$instance instanceof self)){ self::$instance = new self(); } return self::$instance; } //克隆方法私有化,防止复制实例 private function __clone(){}}
工廠模式,工廠方法或類別生成對象,而不是在程式碼中直接new。
使用方法 new實例化類,每次實例化只需呼叫工廠類別中的方法實例化即可。
優點:由於一個類別可能會在很多地方被實例化。當類別名稱或參數變更時,工廠模式可簡單快速的在工廠類別下的方法中一次性修改,避免了一個個的去修改實例化的物件
Test1.php
<?php class Test1 { static function test() { echo FILE; } }Factory.php <?php class Factory { /** *如果某个类在很多的文件中都new ClassName(),那么万一这个类的名字 *发生变更或者参数发生变化,如果不使用工厂模式,就需要修改每一个PHP *代码,使用了工厂模式之后,只需要修改工厂类或者方法就可以了。 */ static function createDatabase() { $test = new Test1(); return $test; } } Test.php <?php spl_autoload_register('autoload1'); $test = Factory::createDatabase(); $test->test();function autoload1($class) { $dir = __DIR__; $requireFile = $dir."\".$class.".php"; require $requireFile; }} Test1.php <?php class Test1 { protected static tt) { echo "对象已经创建<br>"; return self::tt = new Test1(); echo "创建对象<br>"; return self::$tt; } }function echoHello() { echo "Hello<br>"; }} Test.php <?php spl_autoload_register('autoload1'); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello();function autoload1($class) { $dir = __DIR__; $requireFile = $dir."\".$class.".php"; require $requireFile; }}
舉個例子,假設矩形、圓都有同樣的一個方法,那麼我們用基底類別提供的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); echo "<br>";// object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) } circle);
註冊模式,解決全域共用和交換物件。已經創建好的對象,掛在到某個全域可以使用的數組上,在需要使用的時候,直接從該數組上獲取即可。將物件註冊到全域的樹上。任何地方直接去訪問。
<?php class Register { protected static $objects;//将对象注册到全局的树上 function set($alias,$object) { self::$objects[$alias] = $object;//将对象放到树上 } static function get($name) { return self::$objects[$name];//获取某个注册到树上的对象 } function _unset($alias) { unset(self::$objects[$alias]);//移除某个注册到树上的对象。 }}
策略模式,將一組特定的行為和演算法封裝成類,以適應某些特定的上下文環境。
eg:如果有一個電商網站系統,針對男性女性使用者要各自跳到不同的商品類目,並且所有的廣告位展示不同的廣告。在傳統的代碼中,都是在系統中加入各種if else的判斷,硬編碼的方式。如果有一天增加了一種用戶,就需要改寫程式碼。使用策略模式,如果新增加一種使用者類型,只需要增加一種策略就可以。其他所有的地方只需要使用不同的策略就可以。
首先聲明策略的介面文件,約定了策略的包含的行為。然後,定義各個特定的策略實作類別。
UserStrategy.php
<?php /*• 声明策略文件的接口,约定策略包含的行为 */interface UserStrategy { function showAd(); function showCategory(); }FemaleUser.php <?phprequire_once 'Loader.php'; class FemaleUser implements UserStrategy { function showAd() { echo "2016冬季女装"; }function showCategory(){ echo "女装"; }} MaleUser.php <?phprequire_once 'Loader.php'; class MaleUser implements UserStrategy { function showAd(){ echo "IPhone6s"; }function showCategory(){ echo "电子产品"; }} Page.php//执行文件 <?php require_once 'Loader.php'; class Page { protected $strategy;function index(){ echo "AD"; $this->strategy->showAd(); echo "<br>"; echo "Category"; $this->strategy->showCategory(); echo "<br>"; } function setStrategy(UserStrategy $strategy){ $this->strategy = $strategy; }} $page = new Page(); if(isset($_GET['male'])){ $strategy = new MaleUser(); }else { $strategy = new FemaleUser(); }strategy); $page->index();
總結:
透過以上方式,可以發現,在不同使用者登入時顯示不同的內容,但是解決了在顯示時的硬編碼的問題。如果要增加一種策略,只需要增加一種策略實作類別,然後在入口檔案中執行判斷,傳入這個類別即可。實作了解耦。實作依賴倒置和控制反轉 (有待理解); 透過介面的方式,使得類別和類別之間不直接依賴。在使用該類別的時候,才動態的傳入該介面的實作類別。如果要替換某個類,只需要提供一個實作了該介面的實作類,透過修改一行程式碼即可完成替換。
观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新(一个对象通过提供方法允许另一个对象即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者)
场景1:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。
场景2: 用户登录,需要写日志,送积分,参与活动等;使用消息队列,把用户和日志,积分,活动之间解耦合
观察者模式实现了低耦合,非侵入式的通知与更新机制。
<?php /* 观察者接口 */ interface InterfaceObserver { function onListen($sender, $args); function getObserverName(); }// 可被观察者接口 interface InterfaceObservable { function addObserver(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(observerinstanceofInterfaceObserver) { $this->observers[] = $observer; } }public function removeObserver(this->observersas $index => observer->getObserverName() === this->observers, $index, 1); return; } } } }// 模拟一个可以被观察的类 class A extends Observable { public function addListener(this->observersas $observer) { this, $listener); } } }// 模拟一个观察者类 class B extends Observer { protected $observer_name = 'B';public function onListen($sender, sender); echo "<br>"; var_dump($args); echo "<br>"; } }// 模拟另外一个观察者类 class C extends Observer { protected $observer_name = 'C';public function onListen($sender, sender); echo "<br>"; var_dump($args); echo "<br>"; } }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"
装饰器模式, 根据运行时不同的情景动态地为某个对象调用前后添加不同的行
一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重写实现类的方法,使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大额灵活性
场景:
1.symfony 控制器中beforepost afterpost 中post提交前和提交后,对数据处理
2.当某一功能或方法draw,要满足不同的功能需求时,可以使用装饰器模式
/** • 输出一个字符串 • 装饰器动态添加功能 • 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() { 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->addDecorator(new ColorDecorator('red')); //增加装饰器 echo->Index(); //输出<dis style='color: red'><dis style='font-size: 22px'>你好,我是装饰器。</div></div>
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。例如: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";olduser); echo $newuser->getUserName()."n";
推荐学习:《PHP视频教程》
以上是PHP中幾種常見的開發模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!