溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP中常見(jiàn)的開(kāi)發(fā)模式有哪些及怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2023-01-03 14:38:11 來(lái)源:億速云 閱讀:130 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“PHP中常見(jiàn)的開(kāi)發(fā)模式有哪些及怎么實(shí)現(xiàn)”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“PHP中常見(jiàn)的開(kāi)發(fā)模式有哪些及怎么實(shí)現(xiàn)”文章能幫助大家解決問(wèn)題。

設(shè)計(jì)模式六大原則

開(kāi)放封閉原則:一個(gè)軟件實(shí)體如類、模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。

里氏替換原則:所有引用基類的地方必須能透明地使用其子類的對(duì)象.

依賴倒置原則:高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié);細(xì)節(jié)應(yīng)該依賴抽象。

單一職責(zé)原則:不要存在多于一個(gè)導(dǎo)致類變更的原因。通俗的說(shuō),即一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé)。

接口隔離原則:客戶端不應(yīng)該依賴它不需要的接口;一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上。

迪米特法則:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解。

1.單例模式:

特點(diǎn): 使用單例模式, 則可以避免大量的new 操作消耗的資源

單例類不能直接實(shí)例化創(chuàng)建,而是只能由類本身實(shí)例化。因此,要獲得這樣的限制效果,構(gòu)造函數(shù)必須標(biāo)記為private,從而防止類被實(shí)例化。

需要一個(gè)私有靜態(tài)成員變量來(lái)保存類實(shí)例和公開(kāi)一個(gè)能訪問(wèn)到實(shí)例的公開(kāi)靜態(tài)方法。

在PHP中,為了防止他人對(duì)單例類實(shí)例克隆,通常還為其提供一個(gè)空的私有__clone()方法。

  • $_instance必須聲明為靜態(tài)的私有變量

  • 構(gòu)造函數(shù)和析構(gòu)函數(shù)必須聲明為私有,防止外部程序new 類從而失去單例模式的意義

  • getInstance()方法必須設(shè)置為公有的,必須調(diào)用此方法 以返回實(shí)例的一個(gè)引用

  • ::操作符只能訪問(wèn)靜態(tài)變量和靜態(tài)函數(shù)

  • new對(duì)象都會(huì)消耗內(nèi)存

  • 使用場(chǎng)景:最常用的地方是數(shù)據(jù)庫(kù)連接。

  • 使用單例模式生成一個(gè)對(duì)象后, 該對(duì)象可以被其它眾多對(duì)象所使用。

  • 私有的__clone()方法防止克隆對(duì)象

<?php

class Singleton{

//私有屬性,用于保存實(shí)例

private static $instance;

//構(gòu)造方法私有化,防止外部創(chuàng)建實(shí)例

private function __construct(){}//公有方法,用于獲取實(shí)例
public static function getInstance(){
    //判斷實(shí)例有無(wú)創(chuàng)建,沒(méi)有的話創(chuàng)建實(shí)例并返回,有的話直接返回
    if(!(self::$instance instanceof self)){
        self::$instance = new self();
    }
    return self::$instance;
}
//克隆方法私有化,防止復(fù)制實(shí)例
private function __clone(){}}

2.工廠模式

工廠模式,工廠方法或者類生成對(duì)象,而不是在代碼中直接new。

使用方法 new實(shí)例化類,每次實(shí)例化只需調(diào)用工廠類中的方法實(shí)例化即可。

優(yōu)點(diǎn):由于一個(gè)類可能會(huì)在很多地方被實(shí)例化。當(dāng)類名或參數(shù)發(fā)生變化時(shí),工廠模式可簡(jiǎn)單快捷的在工廠類下的方法中一次性修改,避免了一個(gè)個(gè)的去修改實(shí)例化的對(duì)象

Test1.php

<?php

class Test1

{

static function test()

{

echo FILE;

}

}Factory.php

<?php

class Factory

{

/**

*如果某個(gè)類在很多的文件中都new ClassName(),那么萬(wàn)一這個(gè)類的名字

*發(fā)生變更或者參數(shù)發(fā)生變化,如果不使用工廠模式,就需要修改每一個(gè)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 "對(duì)象已經(jīng)創(chuàng)建<br>";

return self::tt = new Test1();

echo "創(chuàng)建對(duì)象<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; 
}}

舉個(gè)例子,假設(shè)矩形、圓都有同樣的一個(gè)方法,那么我們用基類提供的API來(lái)創(chuàng)建實(shí)例時(shí),通過(guò)傳參數(shù)來(lái)自動(dòng)創(chuàng)建對(duì)應(yīng)的類的實(shí)例,他們都有獲取周長(zhǎng)和面積的功能

<?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);

3.注冊(cè)模式

注冊(cè)模式,解決全局共享和交換對(duì)象。已經(jīng)創(chuàng)建好的對(duì)象,掛在到某個(gè)全局可以使用的數(shù)組上,在需要使用的時(shí)候,直接從該數(shù)組上獲取即可。將對(duì)象注冊(cè)到全局的樹(shù)上。任何地方直接去訪問(wèn)。

<?php

class Register

{

protected static $objects;//將對(duì)象注冊(cè)到全局的樹(shù)上 
function set($alias,$object)
{ 
    self::$objects[$alias] = $object;//將對(duì)象放到樹(shù)上 
} 

static function get($name)
{ 
    return self::$objects[$name];//獲取某個(gè)注冊(cè)到樹(shù)上的對(duì)象 
} 

function _unset($alias)
{ 
    unset(self::$objects[$alias]);//移除某個(gè)注冊(cè)到樹(shù)上的對(duì)象。
}}

4.策略模式

策略模式,將一組特定的行為和算法封裝成類,以適應(yīng)某些特定的上下文環(huán)境。
eg:假如有一個(gè)電商網(wǎng)站系統(tǒng),針對(duì)男性女性用戶要各自跳轉(zhuǎn)到不同的商品類目,并且所有的廣告位展示不同的廣告。在傳統(tǒng)的代碼中,都是在系統(tǒng)中加入各種if else的判斷,硬編碼的方式。如果有一天增加了一種用戶,就需要改寫(xiě)代碼。使用策略模式,如果新增加一種用戶類型,只需要增加一種策略就可以。其他所有的地方只需要使用不同的策略就可以。
首先聲明策略的接口文件,約定了策略的包含的行為。然后,定義各個(gè)具體的策略實(shí)現(xiàn)類。
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 "電子產(chǎn)品"; 
}}
Page.php//執(zhí)行文件
<?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();

總結(jié):

通過(guò)以上方式,可以發(fā)現(xiàn),在不同用戶登錄時(shí)顯示不同的內(nèi)容,但是解決了在顯示時(shí)的硬編碼的問(wèn)題。如果要增加一種策略,只需要增加一種策略實(shí)現(xiàn)類,然后在入口文件中執(zhí)行判斷,傳入這個(gè)類即可。實(shí)現(xiàn)了解耦。 實(shí)現(xiàn)依賴倒置和控制反轉(zhuǎn) (有待理解); 通過(guò)接口的方式,使得類和類之間不直接依賴。在使用該類的時(shí)候,才動(dòng)態(tài)的傳入該接口的一個(gè)實(shí)現(xiàn)類。如果要替換某個(gè)類,只需要提供一個(gè)實(shí)現(xiàn)了該接口的實(shí)現(xiàn)類,通過(guò)修改一行代碼即可完成替換。

5.觀察者模式

觀察者模式(Observer),當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生變化時(shí),依賴它的對(duì)象全部會(huì)收到通知,并自動(dòng)更新(一個(gè)對(duì)象通過(guò)提供方法允許另一個(gè)對(duì)象即觀察者 注冊(cè)自己)使本身變得可觀察。當(dāng)可觀察的對(duì)象更改時(shí),它會(huì)將消息發(fā)送到已注冊(cè)的觀察者)
場(chǎng)景1:一個(gè)事件發(fā)生后,要執(zhí)行一連串更新操作。傳統(tǒng)的編程方式,就是在事件的代碼之后直接加入處理的邏輯。當(dāng)更新的邏輯增多之后,代碼會(huì)變得難以維護(hù)。這種方式是耦合的,侵入式的,增加新的邏輯需要修改事件的主體代碼。

場(chǎng)景2: 用戶登錄,需要寫(xiě)日志,送積分,參與活動(dòng)等;使用消息隊(duì)列,把用戶和日志,積分,活動(dòng)之間解耦合

觀察者模式實(shí)現(xiàn)了低耦合,非侵入式的通知與更新機(jī)制。

<?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;

}

}

}

}// 模擬一個(gè)可以被觀察的類

class A extends Observable

{

public function addListener(this->observersas $observer)

{
this, $listener);

}

}

}// 模擬一個(gè)觀察者類

class B extends Observer

{

protected $observer_name = 'B';public function onListen($sender, sender);

echo "<br>";

var_dump($args);

echo "<br>";

}

}// 模擬另外一個(gè)觀察者類

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"

6.裝飾器模式

裝飾器模式, 根據(jù)運(yùn)行時(shí)不同的情景動(dòng)態(tài)地為某個(gè)對(duì)象調(diào)用前后添加不同的行
一個(gè)類提供了一項(xiàng)功能,如果要在修改并添加額外的功能,傳統(tǒng)的編程模式,需要寫(xiě)一個(gè)子類繼承它,并重寫(xiě)實(shí)現(xiàn)類的方法,使用裝飾器模式,僅需要在運(yùn)行時(shí)添加一個(gè)裝飾器對(duì)象即可實(shí)現(xiàn),可以實(shí)現(xiàn)最大額靈活性

場(chǎng)景:

1.symfony 控制器中beforepost afterpost 中post提交前和提交后,對(duì)數(shù)據(jù)處理

2.當(dāng)某一功能或方法draw,要滿足不同的功能需求時(shí),可以使用裝飾器模式

/**
? 輸出一個(gè)字符串
? 裝飾器動(dòng)態(tài)添加功能
? Class EchoText

*/

class EchoText

{

protected $decorator = [];
public function Index()

{

//調(diào)用裝飾器前置操作

$this->beforeEcho();

echo "你好,我是裝飾器。";

//調(diào)用裝飾器后置操作

$this->afterEcho();

}
//增加裝飾器

public function addDecorator(Decorator $decorator)

{

$this->decorator[] = $decorator;

}
//執(zhí)行裝飾器前置操作 先進(jìn)先出原則

protected function beforeEcho()

{

foreach ($this->decorator as $decorator)

$decorator->before();

}
//執(zhí)行裝飾器后置操作 先進(jìn)后出原則

protected function afterEcho()

{
this->decorator);

foreach ($tmp as $decorator)

$decorator->after();

}

}/**
? 裝飾器接口
? Class Decorator

*/

interface Decorator

{

public function before();
public function after();

}/**
? 顏色裝飾器實(shí)現(xiàn)
? 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>";

}

}/**
? 字體大小裝飾器實(shí)現(xiàn)
? 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>";

}

}//實(shí)例化輸出類
echo->addDecorator(new ColorDecorator('red'));

//增加裝飾器
echo->Index();

//輸出<dis style='color: red'><dis style='font-size: 22px'>你好,我是裝飾器。</div></div>

7.適配器模式

將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另一個(gè)接口,適配器模式使得原本的由于接口不兼容而不能一起工作的那些類可以一起工作。
場(chǎng)景:老代碼接口不適應(yīng)新的接口需求,或者代碼很多很亂不便于繼續(xù)修改,或者使用第三方類庫(kù)。例如:php連接數(shù)據(jù)庫(kù)的方法:mysql,,mysqli,pdo,可以用適配器統(tǒng)一

//老的代碼

class User {private $name;      

function __construct($name) {      
    $this->name = $name;      
}      

public function getName() {      
    return $this->name;      
}}
//新代碼,開(kāi)放平臺(tái)標(biāo)準(zhǔn)接口

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";

關(guān)于“PHP中常見(jiàn)的開(kāi)發(fā)模式有哪些及怎么實(shí)現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問(wèn)一下細(xì)節(jié)
AI