面向对象的设计模式及魔术函数
1.工廠模式:?????
a.概述:???? 工廠模式主要是為創建對象提供過渡接口,以便將創建對象的具體過程(new 關鍵字和具體的構造器)隱藏起來。用一個工廠方法來替代,對外提供的只是一個工廠方法,達到提高靈活性的目的。?
?????b.優點:?
?????????? 1.隱藏了new關鍵字和構造器?
?????????? 2.降低了這個對象與別的類之間的耦合度,提高了程序的可擴展性。?
???????????? 原因:當子類被別的類替代,或者構造器的參數發生變化的時候,只需改動工廠方法內的new即可,改動量降到了最低,而如果不用工廠模式,而是直接用new關鍵字的話,需要改動的地方就很多了?
?????????? 3.把對象的設計和實現分割開來,從而代碼擴展性強、靈活性高。?
???? c.工廠模式的使用范圍:?
?????? 當遇到下面的情況時,開發人員可以考慮采用工廠模式:?
?????? * 在編碼時不能預見需要創建哪一個種類的實例。?
?????? * 一個類使用它的子類來創建對象。?
?????? * 開發人員不希望創建了那個類的實例以及如何創建實例的信息暴露給外部程序。?
????? 除了上面提到的例子,工廠模式的實現方式還允許有一些小小的變化,例如:?
?????? * 基類可以是一個抽象類,在這種情況下,工廠類必須返回一個非抽象類。?
?????? * 基類提供了一些缺省方法,只有當這些缺省方法不能滿足特殊需求的情況下才能在子類中重寫這些方法。?
?????? * 可以直接通過傳遞給工廠類的參數決定應該返回哪一個子類的實例。?
???? d. 使用工廠模式,它的設計期于運行期的對象不同,這樣就增強了代碼的可擴展性。?
??????? 它把構造器隱藏了起來,降低了代碼的耦合度,增強了代碼的復用性。?
??????? 工廠模式與new的比較:如果使用new關鍵字的話,那么如果這個類的對象在很多的地方用到,必須要使用多次的new操作,這樣容易引起代碼的重復使用,如果需要改動或者替換成這個類的子類對象,那么,就需要把執行了new操作的所有地方都要改,比較麻煩。而工廠模式,因為它代替了構造器和new關鍵字,而且,它是使用面向接口的,所以,需要這個類的對象的時候,只需要調用這個方法就可以了,如果,需要改動或者替換成這個類的子類對象。只要修改這個工廠里面的內容,而其他的地方都不需要改動。?
??????????工廠模式的結構是:用一個方法來代替new關鍵字和構造器。?
?
工廠模式相當于創建實例對象的new,經常要根據類Class生成實例對象,如A a=new A() 工廠模式也是用來創建實例對象的,工廠模式是現今最常用的模式,在Java程序系統中隨處可見。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php class?YunSuan { ????public?$a; ????public?$b; ????//寫一個空方法,讓子類繼承重寫父類 ????public?function?Suan() ????{ ????????? ????} } class?Jia?extends?YunSuan { ????public?function?Suan() ????{ ????????return?$this->a+$this->b; ????}?? } //工廠模式 //工廠類:生產對象 class?GongChang { ????static?function?ShengChan($ysf) ????{ ????????switch($ysf) ????????{ ????????????case?"+": ????????????????return?new?Jia(); ????????????????break; ????????????case?"-": ????????????????return?new?Jian(); ????????????????break; ????????} ????????????? ????} } $jia?= GongChang::ShengChan("+"); $jia->a = 10; $jia->b = 10; echo?$jia->Suan(); //結果為20 |
?2. ?單例模式:?
??
?? 一、單例模式的四大特征:?
??懶漢式:?
??????? 1。聲明一個私有的,靜態的本類對象,但并不在聲明的時候就初始化,因此,它? 的值為null。?
??????? 2。私有化構造器?
??????? 3。對外提供一個全局的,共有的,靜態的,唯一的方法,用來獲得該實例,但注意的是:必須要手動保持線程同步(synchronized)?
??????? 4.在該方法里,判斷對象是否為null,如果是null的話,表示這個類還沒有被實例化,就會初始化這個對象,再返回如果不是null的話,就直接返回。?
??餓漢式:?
??????? 1.聲明一個私有的,靜態的本類對象,并在聲明的時候就初始化?
??????? 2.私有構造器?
??????? 3.對外提供一個全局的,共有的,靜態的,唯一的方法,用來獲得該實例(餓漢式線程本身就是同步的)?
??????? 4.在該方法里,直接返回該對象即可?
??? 從資源利用效率角度來講,這個比懶漢式單例類稍微差些。從速度和反應時間角度來講,則比懶漢式單例類稍好些。?
????
???? 二、它能解決什么問題:?
????? 它確保一個類在java虛擬機里只有一個實例,使一個類只有一個對象,整個系統共享這個對象。?
???? 三、什么時候使用懶漢式和餓漢式:?
???????? 1。 在使用的幾率很少的情況下使用懶漢式。 --用的時候實例?
???????? 2。 而使用的幾率很高的話就用餓漢式。--一開始就初始化實例?
???? 四、單例模式的好處:?
???????? 整個系統中的所有的類共用一個實例化對象,這樣可以有效的節省資源。?
優點:
1. 改進系統的設計
2. 是對全局變量的一種改進
缺點:
1. 難于調試
2. 隱藏的依賴關系
3. 無法用錯誤類型的數據覆寫一個單例
單例模式的目的是將類只能造一個對象出來
單例模式的主要方法是:將構造 變成私有的-->做一個靜態的生成對象的方法-->造一個靜態的存儲對象-->return 靜態的對象
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php class?DBDA { ????//連接數據庫的類讓他只能造一個對象出來,在不加任何控制的時候可以造很多的類出來 ????//在造對象的時候會調用構造的方法, ????//把構造方法變成私有的就可以可以控制住 ????public?static?$dx;//存儲對象 ????//把構造做為私有 ????private?function?__construct() ????{ ????????????? ????}?? ????//生成對象 ????static?function?DuiXiang() ????{ ????????if(empty(self::$dx)) ????????{ ????????????self::$dx?=?new?DBDA();?//調用靜態對象 ????????} ????????return?self::$dx; ????} } //DBDA::DuiXiang();//調用靜態方法 $db?= DBDA::DuiXiang(); |
面向對象的設計原則:
OOD基本上有6大原則,而實際上都是互補的,也就是說一些原則需要利用另一些原則來實現自己。6大原則如下:
1) Open-Close Principle(OCP),開-閉原則,講的是設計要對擴展有好的支持,而對修改要嚴格限制。這是最重要也是最為抽象的原則,基本上我們所說的Reusable Software既是基于此原則而開發的。其他的原則也是對它的實現提供了路徑。
2) Liskov Substituition Principle(LSP),里氏代換原則,很嚴格的原則,規則是“子類必須能夠替換基類,否則不應當設計為其子類?!币簿褪钦f,子類只能去擴展基類,而不是隱藏或覆蓋基類。
3) Dependence Inversion Principle(DIP),依賴倒換原則,“設計要依賴于抽象而不是具體化”。換句話說就是設計的時候我們要用抽象來思考,而不是一上來就開始劃分我需要哪些哪些類,因為這些是具體。這樣做有什么好處呢?人的思維本身實際上就是很抽象的,我們分析問題的時候不是一下子就考慮到細節,而是很抽象的將整個問題都構思出來,所以面向抽象設計是符合人的思維的。另外這個原則會很好的支持OCP,面向抽象的設計使我們能夠不必太多依賴于實現,這樣擴展就成為了可能,這個原則也是另一篇文章《Design by Contract》的基石。
4) Interface Segregation Principle(ISP),接口隔離原則,“將大的接口打散成多個小接口”,這樣做的好處很明顯,我不知道有沒有必要再繼續描述了,為了節省篇幅,實際上我對這些原則只是做了一個小總結,如果有需要更深入了解的話推薦看《Java與模式》,MS MVP的一:本巨作!^_^
5) 單一職責:一個類的功能盡量單一,降低耦合
6) Law of Demeter or Least Knowlegde Principle(LoD or LKP),迪米特法則或最少知識原則,這個原則首次在Demeter系統中得到正式運用,所以定義為迪米特法則。它講的是“一個對象應當盡可能少的去了解其他對象”。也就是又一個關于如何松耦合(Loosely-Coupled)的法則。
好了,以上是6大原則(或法則)的介紹,對這些原則的深入研究正是如何得到設計模式的道路。在進行了深入了解后我們就可以開始看看設計模式了,設計模式正是對這些法則的應用,著名的設計模式有四人幫(Gang of Four,GoF)的23個模式,除此之外還有很多其他的一些著名模式,大家可以慢慢研究,如果能自己產出一兩個模式的話那就太好了,證明你也是高手了!^_^
魔術函數
1.__construct()
PHP 構造方法 __construct() 允許在實例化一個類之前先執行構造方法。
構造方法
構造方法是類中的一個特殊方法。當使用 new 操作符創建一個類的實例時,構造方法將會自動調用,其名稱必須是 __construct() 。
在一個類中只能聲明一個構造方法,而是只有在每次創建對象的時候都會去調用一次構造方法,不能主動的調用這個方法,所以通常用它執行一些有用的初始化任務。該方法無返回值。
語法:
function __construct(arg1,arg2,...) {...... }例子:
<?php class Person {var $name;var $age;//定義一個構造方法初始化賦值function __construct($name, $sex, $age) {$this->name=$name;$this->age=$age;}function say() {echo "我的名字叫:".$this->name."<br />";echo "我的年齡是:".$this->age;} }$p1=new Person("張三", 20); $p1->say(); ?>運行該例子,輸出:
我的名字叫:張三 的年齡是:20在該例子中,通過構造方法對對象屬性進行初始化賦值。
提示
PHP 不會在本類的構造方法中再自動的調用父類的構造方法。要執行父類的構造方法,需要在子類的構造方法中調用 parent::__construct() 。
2。__destruct()?
當刪除一個對象或對象操作終止時被調用。
PHP 析構方法 __destruct() 允許在銷毀一個類之前執行執行析構方法。
析構方法
與構造方法對應的就是析構方法,析構方法允許在銷毀一個類之前執行的一些操作或完成一些功能,比如說關閉文件、釋放結果集等。析構函數不能帶有任何參數,其名稱必須是 __destruct() 。
語法:
function __destruct() {...... }我們在上面的例子中加入下面的析構方法:
//定義一個析構方法 function __destruct() {echo "再見".$this->name; }再次運行該例子,輸出:
我的名字叫:張三 的年齡是:20 再見張三提示
3。__call()?
對象調用某個方法,?
若方法存在,則直接調用;?
若不存在,則會去調用__call函數。
__call() 方法用于監視錯誤的方法調用。
__call()(Method overloading)
為了避免當調用的方法不存在時產生錯誤,可以使用 __call() 方法來避免。該方法在調用的方法不存在時會自動調用,程序仍會繼續執行下去。
語法:
function __call(string $function_name, array $arguments) {...... }該方法有兩個參數,第一個參數 $function_name 會自動接收不存在的方法名,第二個 $args 則以數組的方式接收不存在方法的多個參數。
在類里面加入:
function __call($function_name, $args) {echo "你所調用的函數:$function_name(參數:<br />";var_dump($args);echo ")不存在!"; }當調用一個不存在的方法時(如 test() 方法):
$p1=new Person(); $p1->test(2,"test");輸出的結果如下:
你所調用的函數:test(參數: array(2) {[0]=>int(2)[1]=>string(4) "test" } )不存在!4。__get()?
讀取一個對象的屬性時,?
若屬性存在,則直接返回屬性值;?
若不存在,則會調用__get函數
- __set()?方法用于設置私有屬性值。
實際應用中,經常會把類的屬性設置為私有(private),那么需要對屬性進行訪問時,就會變得麻煩。雖然可以將對屬性的訪問寫成一個方法來實現,但 PHP 提供了一些特殊方法來方便此類操作。
__set()
__set() 方法用于設置私有屬性值:
function __set($property_name, $value) { $this->$property_name = $value; }在類里面使用了 __set() 方法后,當使用 $p1->name = "張三"; 這樣的方式去設置對象私有屬性的值時,就會自動調用 __set() 方法來設置私有屬性的值。
5。__set()?
設置一個對象的屬性時,?
若屬性存在,則直接賦值;?
若不存在,則會調用__set函數。
- __get()?方法用于獲取私有屬性值。
__get()
__get() 方法用于獲取私有屬性值:
function __set($property_name, $value) { return isset($this->$property_name) ? $this->$property_name : null; }例子:
<?php class Person {private $name;private $sex;private $age;//__set()方法用來設置私有屬性function __set($property_name, $value) { echo "在直接設置私有屬性值的時候,自動調用了這個 __set() 方法為私有屬性賦值<br />";$this->$property_name = $value; }//__get()方法用來獲取私有屬性function __get($property_name) { echo "在直接獲取私有屬性值的時候,自動調用了這個 __get() 方法<br />";return isset($this->$property_name) ? $this->$property_name : null;} }$p1=new Person(); //直接為私有屬性賦值的操作, 會自動調用 __set() 方法進行賦值 $p1->name = "張三"; //直接獲取私有屬性的值, 會自動調用 __get() 方法,返回成員屬性的值 echo "我的名字叫:".$p1->name; ?>運行該例子,輸出:
在直接設置私有屬性值的時候,自動調用了這個 __set() 方法為私有屬性賦值 在直接獲取私有屬性值的時候,自動調用了這個 __get() 方法 我的名字叫:張三6。__toString()?
打印一個對象的時被調用。如echo $obj;或print $obj;
7。__clone()?
克隆對象時被調用。如:$t=new Test();$t1=clone $t;
clone 關鍵字用于克隆一個完全一樣的對象,__clone() 方法來重寫原本的屬性和方法。
對象克隆
有的時候我們需要在一個項目里面使用兩個或多個一樣的對象,如果使用 new 關鍵字重新創建對象,再賦值上相同的屬性,這樣做比較煩瑣而且也容易出錯。PHP 提供了對象克隆功能,可以根據一個對象完全克隆出一個一模一樣的對象,而且克隆以后,兩個對象互不干擾。
使用關鍵字 clone 來克隆對象。語法:
$object2 = clone $object;例子:
<?php class Person {private $name;private $age;function __construct($name, $age) {$this->name=$name;$this->age=$age;}function say() {echo "我的名字叫:".$this->name."<br />";echo "我的年齡是:".$this->age;} }$p1 = new Person("張三", 20); $p2 = clone $p1; $p2->say(); ?>運行例子,輸出:
我的名字叫:張三 我的年齡是:20__clone()
如果想在克隆后改變原對象的內容,需要在類中添加一個特殊的 __clone() 方法來重寫原本的屬性和方法。__clone() 方法只會在對象被克隆的時候自動調用。
例子:
<?php class Person {private $name;private $age;function __construct($name, $age) {$this->name = $name;$this->age = $age;}function say() {echo "我的名字叫:".$this->name;echo " 我的年齡是:".$this->age."<br />";}function __clone() {$this->name = "我是假的".$this->name;$this->age = 30;} }$p1 = new Person("張三", 20); $p1->say(); $p2 = clone $p1; $p2->say(); ?>運行例子,輸出:
我的名字叫:張三 我的年齡是:20 我的名字叫:我是假的張三 我的年齡是:308。__sleep()?
serialize之前被調用。若對象比較大,想刪減一點東東再序列化,可考慮一下此函數。
9。__wakeup()?
unserialize時被調用,做些對象的初始化工作。
10。__isset()?
檢測一個對象的屬性是否存在時被調用。如:isset($c->name)。
__isset()
__isset() 方法用于檢測私有屬性值是否被設定。
如果對象里面成員是公有的,可以直接使用 isset() 函數。如果是私有的成員屬性,那就需要在類里面加上一個 __isset() 方法:
private function __isset($property_name) {return isset($this->$property_name); }這樣當在類外部使用 isset() 函數來測定對象里面的私有成員是否被設定時,就會自動調用 __isset() 方法來檢測。
11。__unset()?
unset一個對象的屬性時被調用。如:unset($c->name)。
__unset()
__unset() 方法用于刪除私有屬性。
同 isset() 函數一樣,unset() 函數只能刪除對象的公有成員屬性,當要刪除對象內部的私有成員屬性時,需要使用__unset() 方法:
private function __unset($property_name) {unset($this->$property_name); }12。__set_state()?
調用var_export時,被調用。用__set_state的返回值做為var_export的返回值。
13。__autoload()?
實例化一個對象時,如果對應的類不存在,則該方法被調用。
__autoload() 方法用于自動加載類。
__autoload()
在實際項目中,不可能把所有的類都寫在一個 PHP 文件中,當在一個 PHP 文件中需要調用另一個文件中聲明的類時,就需要通過 include 把這個文件引入。不過有的時候,在文件眾多的項目中,要一一將所需類的文件都 include 進來,一個很大的煩惱是不得不在每個類文件開頭寫一個長長的包含文件的列表。我們能不能在用到什么類的時候,再把這個類所在的 php 文件導入呢?
為此,PHP 提供了 __autoload() 方法,它會在試圖使用尚未被定義的類時自動調用。通過調用此函數,腳本引擎在 PHP 出錯失敗前有了最后一個機會加載所需的類。
__autoload() 方法接收的一個參數,就是欲加載的類的類名,所以這時候需要類名與文件名對應,如 Person.php ,對應的類名就是 Pserson 。
例子:
Pserson.php
<?php <?php class Person {private $name;private $age;function __construct($name, $age) {$this->name = $name;$this->age = $age;}function say() {echo "我的名字叫:".$this->name."<br />";echo " 我的年齡是:".$this->age;} } ?>test.php
<?php function __autoload($class_name) {require_once $class_name.'.php'; }//當前頁面 Pserson 類不存在則自動調用 __autoload() 方法,傳入參數 Person $p1 = new Person("張三","20"); $p1 -> say(); ?>運行 test.php ,輸出:
我的名字叫:張三 我的年齡是:20魔術常量
1。__LINE__?
返回文件中的當前行號。
2。__FILE__?
返回文件的完整路徑和文件名。如果用在包含文件中,則返回包含文件名。自 PHP 4.0.2 起,__FILE__ 總是包含一個絕對路徑,而在此之前的版本有時會包含一個相對路徑。
3。__FUNCTION__?
返回函數名稱(PHP 4.3.0 新加)。自 PHP 5 起本常量返回該函數被定義時的名字(區分大小寫)。在 PHP 4 中該值總是小寫字母的。
4。__CLASS__?
返回類的名稱(PHP 4.3.0 新加)。自 PHP 5 起本常量返回該類被定義時的名字(區分大小寫)。在 PHP 4 中該值總是小寫字母的。
5。__METHOD__?
返回類的方法名(PHP 5.0.0 新加)。返回該方法被定義時的名字(區分大小寫)。
?
(1)初識魔術方法
Php5.0發布以來為我們提供了很多面向對象的特性,尤其是為我們提供了好多易用的魔術方法,這些魔術方法可以讓我們簡化我們的編碼,更好的設計我們的系統。今天我們就來認識下php5.0給我們提供的魔術方法。
總結
以上是生活随笔為你收集整理的面向对象的设计模式及魔术函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MYSQL 索引相关
- 下一篇: 用什么公式标记B列的重复值?