摘要:的設計模式有很多種,本文取最簡單的三種模式工廠模式單例模式和注冊樹模式進行簡單的講解。文件創建完后,咱們回到單元測試文件文件再執行一下單元測試命令發現,也能返回成功,這樣的話我們就能很方便的修改任何驅動了。
php 設計模式之工廠模式、單例模式、注冊樹模式
在軟件工程中,創建型設計模式承擔著對象創建的職責,嘗試創建適合程序上下文的對象,對象創建設計模式的產生是由于軟件工程設計的問題,具體說是向設計中增加復雜度,創建型設計模式解決了程序設計中對象創建的問題。PHP的設計模式有很多種,本文取最簡單的三種模式: 工廠模式、單例模式和注冊樹模式進行簡單的講解。
工廠模式用工廠方法或者類生成對象,而不是代碼中直接使用 new 關鍵字
比如咱們要做一個連接數據庫的操作,平時都是用mysql。那突然有一天mysql收費了,咋辦?那我們就用Sqlite作來數據庫。如果以傳統的方式創建一個數據庫連接類的話是需要使用關鍵字new MysqlDrive()把這個數據庫實例化,一旦數據庫變更成的話就需要把所有的new MysqlDrive()變更成new SqliteDrive() 這樣替換比較麻煩,并且還容易出錯。所以,下面的工廠模式可以很好的解決這一問題。
廢話不多說,演示一遍就明白了
先看一下目錄結構吧本文演示的全部是遵循PSR-4的編碼規范,當然,是在vendor/目錄下,如果沒有請自己行執行命令composer dumpatuoload 如果您沒有安裝composer那就請看下面文章:
《集成 Composer 包依賴管理》
以下是我的目錄結構:
自動忽略DependencyInjection 跟HttpFoundation目錄,這是我計劃下次寫的東西,嘻嘻...
先看看主要文件的代碼吧:
tests/這個目錄是為了讓咱們方便測試的目錄,也就是單元測試目錄
文件: tests/bootstrap.php
include_once __DIR__."/../../../composer/ClassLoader.php"; $loader = new ComposerAutoloadClassLoader(); $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); $classMaps = [ "Dudulu" => [$vendorDir."/src/"] ]; foreach ($classMaps as $namespace => $path) { $loader->setPsr4($namespace, $path); } $loader->register(true);
咱們需要測試的驅動類MysqlDerive.php
文件: src/DesignPatternsFactoryModeDBMysqlDrive.php
namespace DuduluDesignPatternsFactoryMode; use DuduluDesignPatternsDBMysqlDrive; /** * Class Factory * @package DuduluDesignPatternsFactoryMode */ class Factory { /** * @return MysqlDrive */ public static function database() { return new MysqlDrive(); } }
為了強制讓每種驅動都要有一個連接方式,所以我們需要一個Interface。
文件: src/DesignPatterns/DB/Interfaces/DriveInterface.php
namespace DuduluDesignPatternsDBInterfaces; /** * Interface DriveInterface * @package DuduluDesignPatternsDBInterfaces */ interface DriveInterface { /** * @return mixed */ public function connection(); }普通模式
先看一個普通demo,直接實例化MysqlDrive對象
include_once "../bootstrap.php"; use DuduluDesignPatternsDBMysqlDrive; class FactoryTest extends PHPUnit_Framework_TestCase { public function testConnection() { $db = new MysqlDrive(); $this->assertEquals(true, $db->connection()); } }
進入src/tests/DesignPattens目錄.
命令行執行: phpunit FactoryTest.php可以發現這樣是好使的...
工廠模式工廠模式 是一種類,它具有為您創建對象的某些方法。您可以使用工廠類創建對象,而不直接使用 new。這樣,如果您想要更改所創建的對象類型,只需更改該工廠即可。使用該工廠的所有代碼會自動更改。
首先咱們先創建一個Factory.php作為工廠類,然后里邊實現一個靜態方法對相數據庫驅動進行實例化。
文件: src/DesignPatterns/FactoryMode/Factory.php
namespace DuduluDesignPatternsFactoryMode; use DuduluDesignPatternsDBMysqlDrive; /** * Class Factory * @package DuduluDesignPatternsFactoryMode */ class Factory { /** * @return MysqlDrive */ public static function database() { return new MysqlDrive(); } }
創建完后,咱們回到單元測試文件FactoryTest.php
文件: tests/DesignPattens/FactoryTest.php
include_once "../bootstrap.php"; use DuduluDesignPatternsFactoryModeFactory; class FactoryTest extends PHPUnit_Framework_TestCase { public function testConnection() { $db = Factory::database(); $this->assertEquals(true, $db->connection()); } }
再執行一下單元測試命令發現,也能返回成功,這樣的話我們就能很方便的修改任何驅動了。如果我們從mysql換到sqlite了,那么,咱們主要的代碼都不需要更變,只要在Factory.php把connection方法的邊接方式修改完就好了,非常方便。
單例模式使某個類的對象僅允許創建一個
某些應用程序資源是獨占的,因為有且只有一個此類型的資源。比如,數據庫的連接的獨占。希望在應用程序中共享數據庫連接,因為在保持連接打開或關閉時,它是一種開銷,在獲取單個頁面的過程中更是如此。
比如咱們連接數據庫時,如果不使用單例模式,多個地方都對數據類進行了實例化,那么這樣會造能很多資源浪費,為了解決這問題,對于數據庫類我們只需要實例化一次,后面再次調用它是如果已經實例化,那就直接返回。
來,我們拿一個類來玩一玩...
文件: src/DesignPatterns/SingletonMode/SingletonDB.php
我們創建這個類,然后將構造方法私有化,這樣的話我們就無法使用new關鍵字對這個類進行實例化了。
namespace DuduluDesignPatternsSingletonMode; use DuduluDesignPatternsDBInterfacesDriveInterface; /** * Class SingletonDB * @package DuduluDesignPatternsSingletonMode */ class SingletonDB implements DriveInterface { /** * SingletonDB constructor. */ private function __construct() { } /** * @return bool */ public function connection() { return true; } }
那么我們要如何使用這個對象呢?我們需要一個受保護的成員和一個靜態方法:
/** * @var SingletonDB */ protected static $db; /** * @return SingletonDB */ public static function getInstance() { if (self::$db) { return self::$db; } self::$db = new self(); return self::$db; }
這個方法很好理解,簡單意思就是如果當前屬性已經被設置過了,那就不再進行實例化,而是直接返回,否則實例化當前對象并返回。
與測試上面的方法一樣,測玩玩...
創建測試的文件: tests/DesignPattens/SingletonDBTest.php
include_once "../bootstrap.php"; use DuduluDesignPatternsSingletonModeSingletonDB; /** * Class SingletonDBTest */ class SingletonDBTest extends PHPUnit_Framework_TestCase { /** * @return void */ public function testConnection() { $db = SingletonDB::getInstance(); $this->assertEquals(true, $db->connection()); } }
執行命令: phpunit SingletonDBTest.php 發現也是可以執行成功的。
如果不信的話,你可以試試多執行幾次SingletonDB::getInstance(); 然后在 getInstance() 方法體里做一個計數器,看看它實例化過幾次。
注冊樹模式主要用來解決全局共享和交換對象
這個也很好理解,因為我們在框架中經常用到。
注冊樹模式當然也叫注冊模式,注冊器模式。之所以我在這里矯情一下它的名稱,是因為我感覺注冊樹這個名稱更容易讓人理解。注冊樹模式通過將對象實例注冊到一棵全局的對象樹上,需要的時候從對象樹上采摘的模式設計方法。
咱們結合工廠模式及單例模式做一個小例子:
創建文件: src/DesignPatterns/RegisterMode/Register.php
namespace DuduluDesignPatternsRegisterMode; /** * Class Register * @package DuduluDesignPatternsRegisterMode */ class Register { /** * @var array */ protected static $classMaps = []; /** * @param $alias * @param $class * @return void */ public static function set($alias, $class ) { self::$classMaps[$alias] = $class; } /** * @param $alias * @return mixed */ public static function get($alias ) { return self::$classMaps[$alias]; } }
然后創建一個單例模式的DB類DemoDB.php:
文件: src/DesignPatterns/DB/DemoDB.php
namespace DuduluDesignPatternsDB; use DuduluDesignPatternsDBInterfacesDriveInterface; class DemoDB implements DriveInterface { /** * @var DemoDB */ protected static $db; /** * SingletonDB constructor. */ private function __construct() { } /** * @return DemoDB */ public static function getInstance() { if (self::$db) { return self::$db; } self::$db = new self(); return self::$db; } /** * @return bool */ public function connection() { return true; } }
再工廠模式文件上加入注冊方式代碼:
文件: src/DesignPatterns/FactoryMode/Factory.php
use DuduluDesignPatternsRegisterModeRegister; /** * @return DemoDB */ public static function testDb() { $db = DemoDB::getInstance(); Register::set("DB", $db); return $db; }
最后咱們驗證一下:
在tests/目錄下創建RegisterTest.php文件
include_once "../bootstrap.php"; use DuduluDesignPatternsRegisterModeRegister; use DuduluDesignPatternsDBDemoDB; /** * Class RegisterTest */ class RegisterTest extends PHPUnit_Framework_TestCase { /** * @return void */ public function testConnection() { Register::set("DB", DemoDB::getInstance()); $db = Register::get("DB"); $this->assertEquals(true, $db->connection()); } }
OK 走一個phpunit RegisterTest.php
返回OK,好棒好棒...☆?(ゝ。?)
__ / ))) _ `/ イ~ (((ヽ ( ?  ̄Y\ | (\ ∧_∧?。? ヽ ヽ`( `o′ )/ノ/ \ | ⌒Y⌒ / / |ヽ | ?/ \トー仝ーイ |
GitHub: https://github.com/icowan/dudulu
如果有時間,下次我再寫些關于其他設計模式的文章...
原文地址: 設計模式之工廠模式、單例模式、注冊樹模式
歡迎關注我站點: LatteCake
歡迎關注公眾號: 聰聰實驗室
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30285.html
摘要:一工廠模式工廠方法或類中生成對象,而不是在代碼中直接優點將某個常用類,多個地方需要時,使用工廠模式,方便類的擴展與維護文件目錄正常實例化類獲取單例模式的類將實例化后的類注冊到全局注冊樹中外部調用得到對象獲取全局注冊樹中的對象卸載全局注冊樹中 一、工廠模式:工廠方法或類中生成對象,而不是在代碼中直接 new 優點:將某個常用類,多個地方需要 new 時,使用工廠模式,方便類的擴展與維護文...
摘要:我們今天也來做一個萬能遙控器設計模式適配器模式將一個類的接口轉換成客戶希望的另外一個接口。今天要介紹的仍然是創建型設計模式的一種建造者模式。設計模式的理論知識固然重要,但 計算機程序的思維邏輯 (54) - 剖析 Collections - 設計模式 上節我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進行操作,第二類是返回一個容器接口對象,上節我們介紹了...
摘要:很多接觸的框架就是基于各種模式設計形成的。在所有模式設計中,有三種基礎設計模式,單例模式,工廠模式,注冊樹模式,其他模式往往基于這幾種模式,今天帶來的是單例模式。工廠模式更多考慮的是擴展維護的問題。 (非原創) 一.單例模式 模式設計是什么?初學者一開始會被這高大上的名稱給唬住。而對于有豐富編程經驗的老鳥來說,模式設計又是無處不在。很多接觸的框架就是基于各種模式設計形成的。 簡單說,在...
摘要:結構型模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。行為型模式模版方法模式命令模式迭代器模式觀察者模式中介者模式備忘錄模式解釋器模式模式狀態模式策略模式職責鏈模式責任鏈模式訪問者模式。 主要版本 更新時間 備注 v1.0 2015-08-01 首次發布 v1.1 2018-03-12 增加新技術知識、完善知識體系 v2.0 2019-02-19 結構...
閱讀 1971·2021-09-09 09:33
閱讀 1111·2019-08-30 15:43
閱讀 2657·2019-08-30 13:45
閱讀 3304·2019-08-29 11:00
閱讀 853·2019-08-26 14:01
閱讀 3568·2019-08-26 13:24
閱讀 477·2019-08-26 11:56
閱讀 2686·2019-08-26 10:27