成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

<<深入PHP面向?qū)ο蟆⒛J脚c實(shí)踐>>讀書筆記:面向?qū)ο笤O(shè)計(jì)和過程式編程

xiao7cn / 838人閱讀

摘要:注本文內(nèi)容來深入面向?qū)ο竽J脚c實(shí)踐中節(jié)。面向?qū)ο笤O(shè)計(jì)與過程式編程面向?qū)ο笤O(shè)計(jì)和過程式編程有什么不同呢可能有些人認(rèn)為最大的不同在于面向?qū)ο缶幊讨邪瑢?duì)象。面向?qū)ο缶幊毯瓦^程式編程的一個(gè)核心區(qū)別是如何分配職責(zé)。

注:本文內(nèi)容來<<深入PHP面向?qū)ο?、模式與實(shí)踐>>中6.2節(jié)。

6.2 面向?qū)ο笤O(shè)計(jì)與過程式編程

??面向?qū)ο笤O(shè)計(jì)和過程式編程有什么不同呢?可能有些人認(rèn)為最大的不同在于面向?qū)ο缶幊讨邪瑢?duì)象。事實(shí)上,這種說法不準(zhǔn)確。在PHP中,你經(jīng)常會(huì)發(fā)現(xiàn)過程式編程也使用對(duì)象,如使用一個(gè)數(shù)據(jù)庫類,也可能遇到類中包含過程式代碼的情況。類的出現(xiàn)并不能說明使用了面向?qū)ο笤O(shè)計(jì)。甚至對(duì)于Java這種強(qiáng)制把一切都包含在類中的語音(這個(gè)我可以證明,我在大三的時(shí)候?qū)W過Java),使用對(duì)象也不能說明使用了面向?qū)ο笤O(shè)計(jì)。

??面向?qū)ο缶幊毯瓦^程式編程的一個(gè)核心區(qū)別是如何分配職責(zé)。過程式編程表現(xiàn)為一系列命令和方法的連續(xù)調(diào)用??刂拼a根據(jù)不同的條件執(zhí)行不同的職責(zé)。這種自頂向下的控制方式導(dǎo)致了重復(fù)和相互依賴的代碼遍布于整個(gè)項(xiàng)目。面向?qū)ο缶幊虅t將職責(zé)從客戶端代碼中移到專門的對(duì)象中,盡量減少相互依賴。

??為了說明以上幾點(diǎn),我們分別使用面向?qū)ο蠛瓦^程式代碼的方式來分析一個(gè)簡單的問題。假設(shè)我們要?jiǎng)?chuàng)建一個(gè)用于讀寫配置文件的工具。為了重點(diǎn)關(guān)注代碼的結(jié)構(gòu),示例中將忽略具體的功能實(shí)現(xiàn)。(文后有完整代碼示例,來自于圖靈社區(qū))

??我們先按過程式方式來解決這個(gè)問題。首先,用下面的格式來讀寫文本:

key:value

只需要兩個(gè)函數(shù):

function readParams( $sourceFile ) {
    $params = array();
    // 從$sourceFile中讀取文本參數(shù)
    return $params;
}

function writeParams( $params, $sourceFile ) {
    // 寫入文本參數(shù)到$sourceFile
}

readParams()函數(shù)的參數(shù)為源文件的名稱。該函數(shù)試圖打開文件,讀取每一行內(nèi)容并查找鍵/值對(duì),然后用鍵/值對(duì)構(gòu)建一個(gè)關(guān)聯(lián)數(shù)組。最后,該函數(shù)給控制代碼返回?cái)?shù)組。writeParams()以關(guān)聯(lián)數(shù)組和指向源文件的路徑作為參數(shù),它循環(huán)遍歷關(guān)聯(lián)數(shù)組,將每對(duì)鍵/值對(duì)寫入文件。下面是使用這兩個(gè)函數(shù)的客戶端代碼:

$file = "./param.txt";
$array["key1"] = "vall";
$array["key2"] = "val2";
$array["key3"] = "val3";
writeParams( $array, $file );
$output = readParams( $file );
print_r( $output );

這段代碼較為緊湊并且易于維護(hù)。writeParams()被調(diào)用來創(chuàng)建Param.txt并向其寫入如下的內(nèi)容:

key1:val1
key2:val2
key3:val3

現(xiàn)在,我們被告知這個(gè)工具需要支持如下所示XML格式:


    
        my key
        my val
    

??如果參數(shù)文件以.xml文件結(jié)尾,就應(yīng)該以XML模式讀取參數(shù)文件。雖然這不難調(diào)節(jié),但可能會(huì)使我們的代碼更難維護(hù)。這是我們有兩個(gè)選擇:可以在控制代碼中檢查文件擴(kuò)展名,或者在讀寫函數(shù)中檢測(cè)。我們使用后面那種寫法。:

function readParams( $source ) {
    $params = array();
    if ( preg_match( "/.xml$/i", $source ) ) {
        // 從$source中讀取XML參數(shù)
    } else {
        // $source中讀取文本參數(shù)
    }
    return $params;
}

function writeParams( $params, $source ) {
    if ( preg_match( "/.xml$/i", $source ) ) {
        // 寫入XML參數(shù)到$source
    } else {
        // 寫入文本參數(shù)到$source
    }
}

??如上所示,我們?cè)趦蓚€(gè)函數(shù)中都要檢查XML擴(kuò)展名,這樣的重復(fù)性代碼會(huì)產(chǎn)生問題。如果我們還被要求支持其他格式的參數(shù),就要保持readParams()和writeParams()函數(shù)的一致性。

??下面我們用類來處理相同的問題。首先,創(chuàng)建一個(gè)抽象的基類來定義類型接口:

abstract class ParamHandler {
    protected $source;
    protected $params = array();

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

    function addParam( $key, $val ) {
        $this->params[$key] = $val;
    }

    function getAllParams() {
        return $this->params;
    }

    static function getInstance( $filename ) {
        if ( preg_match( "/.xml$/i", $filename )) {
            return new XmlParamHandler( $filename );
        }
        return new TextParamHandler( $filename );
    }

    abstract function write();
    abstract function read();
}

??我們定義addParam()方法來允許用戶增加參數(shù)到protected屬性$params, getAllParams()則用于訪問該屬性,獲得$params的值。

??我們還創(chuàng)建了靜態(tài)的getInstance()方法來檢測(cè)文件擴(kuò)展名,并根據(jù)文件擴(kuò)展名返回特定的子類。最重要的是,我們定義了兩個(gè)抽象方法read()和write(),確保ParamHandler類的任何子類都支持這個(gè)接口。

??現(xiàn)在,我們定義了多個(gè)子類。為了實(shí)例簡潔,再次忽略實(shí)現(xiàn)細(xì)節(jié):

class XmlParamHandler extends ParamHandler {

    function write() {
        // 寫入XML文件
        // 使用$this->params
    }

    function read() {
        // 讀取XML文件內(nèi)容
        // 并賦值給$this->params
    } 

}

class TextParamHandler extends ParamHandler {

    function write() {
        // 寫入文本文件
        // 使用$this->params
    }

    function read() {
        // 讀取文本文件內(nèi)容
        // 并賦值給$this->params
    } 

}

??這些類簡單地提供了write()和read()方法的實(shí)現(xiàn)。每個(gè)類都將根據(jù)適當(dāng)?shù)奈募袷竭M(jìn)行讀寫。客戶端代碼將完全自動(dòng)地根據(jù)文件擴(kuò)展名來寫入數(shù)據(jù)到文本和XML格式的文件:

$file = "./params.xml"; 
$test = ParamHandler::getInstance( $file );
$test->addParam("key1", "val1" );
$test->addParam("key2", "val2" );
$test->addParam("key3", "val3" );
$test->write(); // 寫入XML格式中

我們還可以從兩種文件格式中讀取:

$test = ParamHandler::getInstance( "./params.txt" );
$test->read(); // 從文本格式中讀取

那么,我們可以從這兩種解決方案中學(xué)習(xí)到什么呢?

職責(zé)

??在過程式編程的例子中,控制代碼的職責(zé)(duties)是判斷文件格式,它判斷了兩次而不是一次。條件語句被綁定到函數(shù)中,但這僅是將判斷的流程影藏起來。對(duì)readParams()的調(diào)用和對(duì)writeParams()的調(diào)用必須發(fā)生在不同的地方,因此我們不得不在每個(gè)函數(shù)中重復(fù)檢測(cè)文件擴(kuò)展名(或執(zhí)行其他檢測(cè)操作)。
??在面向?qū)ο蟠a中,我們?cè)陟o態(tài)方法getInstance()中進(jìn)行文件格式的選擇,并且僅在getInstance()中檢測(cè)文件擴(kuò)展名一次,就可以決定使用哪一個(gè)合適的子類??蛻舳舜a并不負(fù)責(zé)實(shí)現(xiàn)讀寫功能。它不需要知道自己屬于哪個(gè)子類就可以使用給定的對(duì)象。它只需要知道自己在使用ParamHandler對(duì)象,并且ParamHandler對(duì)象支持write()和read()的方法。過程式代碼忙于處理細(xì)節(jié),而面向?qū)ο蟠a只需一個(gè)接口即可工作,并且不要考慮實(shí)現(xiàn)的細(xì)節(jié)。由于實(shí)現(xiàn)由對(duì)象負(fù)責(zé),而不是由客戶端代碼負(fù)責(zé),所以我們能夠很方便地增加對(duì)新格式的支持。

內(nèi)聚

??內(nèi)聚(cohesion)是一個(gè)模塊內(nèi)部各成分之間相互關(guān)聯(lián)程度的度量。理想情況下,你應(yīng)該使各個(gè)組件職責(zé)清晰、分工明確。如果代碼間的關(guān)聯(lián)范圍太廣,維護(hù)就會(huì)很困難--因?yàn)槟阈枰?strong>修改部分代碼的同時(shí)修改相關(guān)代碼。

??前面的ParamHandler類將相關(guān)的處理過程集中起來。用于處理XML的類方法間可以共享數(shù)據(jù),并且一個(gè)類方法中的改變可以很容易地反映到另一個(gè)方法中(比如改變XML元素名)。因此我們可以說ParamHandler類是高度內(nèi)聚的。
??另一方面,過程式的例子則把相關(guān)的過程分離開,導(dǎo)致處理XML的代碼在多個(gè)函數(shù)中同時(shí)出現(xiàn)。

耦合

??當(dāng)系統(tǒng)各部分代碼緊密綁在一起時(shí),就會(huì)產(chǎn)生精密耦合(coupling),這時(shí)在一個(gè)組件中的變化會(huì)迫使其他部件隨之改變。緊密耦合不是過程式代碼特有的,但是過程式代碼比較容易產(chǎn)生耦合問題。
??我們可以在過程代碼中看到耦合的產(chǎn)生。在writeParams()和readParams()函數(shù)中,使用了相同的文件擴(kuò)展名測(cè)試來決定如何處理數(shù)據(jù)。因此我們要改下一個(gè)函數(shù),就不得不同時(shí)改寫另一個(gè)函數(shù)。例如,我們要增加一種新的文件格式,就要在兩個(gè)函數(shù)中按相同的方式都加上相應(yīng)的擴(kuò)展名檢查代碼,這樣兩個(gè)函數(shù)才能保持一致。
??面向?qū)ο蟮氖纠袆t將每個(gè)子類彼此分開,也將其余客戶端代碼分開。如果需要增加新的參數(shù)格式,只需簡單地創(chuàng)建相應(yīng)的子類,并在父類的靜態(tài)方法getInstance()中增加一行文件檢測(cè)代碼即可。

正交

??(orthogonality)指將職責(zé)相關(guān)的組件緊緊結(jié)合在一起,而與外部系統(tǒng)環(huán)境隔開,保持獨(dú)立。在<>(中文名<<程序員修煉之道:從小工到專家 >>)一書中有所介紹。

??正交主張重用組件,期望不需要任何特殊配置就能把一個(gè)組件插入到新系統(tǒng)中。這樣的組件有明確的與環(huán)境無關(guān)的輸入和輸出。正交代碼使修改變得更簡單,因?yàn)樾薷囊粋€(gè)實(shí)現(xiàn)只會(huì)影響到被改動(dòng)的組件本身。最后,正交代碼更加安全。bug的影響只局限于它的作用域之中。內(nèi)部高度相互依賴的代碼發(fā)生錯(cuò)誤時(shí),很容易在系統(tǒng)中引起連鎖反應(yīng)。

??如果只有一個(gè)類,松散耦合和高聚合是無從談起的。畢竟,我們可以把整個(gè)過程示例的全部代碼塞到一個(gè)被誤導(dǎo)的類里。(這想想就挺可怕的。)

職責(zé)和耦合的英文翻譯原文是沒有的,我通過Goole翻譯加上的。
代碼示例

過程式編程

param as $param ) {
            $params["$param->key"] = "$param->val";
        }
    } else {
        $fh = fopen( $source, "r" );
        while ( ! feof( $fh ) ) {
            $line = trim( fgets( $fh ) );
            if ( ! preg_match( "/:/", $line ) ) {
                continue;
            }
            list( $key, $val ) = explode( ":", $line );
            if ( ! empty( $key ) ) {
                $params[$key]=$val;
            }
        }
        fclose( $fh );
    }
    return $params;
}

function writeParams( $params, $source ) {
    $fh = fopen( $source, "w" );
    if ( preg_match( "/.xml$/i", $source )) {
        fputs( $fh, "
" );
        foreach ( $params as $key=>$val ) {
            fputs( $fh, "	
" );
            fputs( $fh, "		$key
" );
            fputs( $fh, "		$val
" );
            fputs( $fh, "	
" );
        }
        fputs( $fh, "
" );
    } else {
        foreach ( $params as $key=>$val ) {
            fputs( $fh, "$key:$val
" );
        }
    }
    fclose( $fh );
}

面向?qū)ο笤O(shè)計(jì)

source = $source;
    }

    function addParam( $key, $val ) {
        $this->params[$key] = $val;
    }

    function getAllParams() {
        return $this->params;
    }

    protected function openSource( $flag ) {
        $fh = @fopen( $this->source, $flag );
        if ( empty( $fh ) ) {
            throw new Exception( "could not open: $this->source!" );
        }
        return $fh;
    }

    static function getInstance( $filename ) {
        if ( preg_match( "/.xml$/i", $filename )) {
            return new XmlParamHandler( $filename );
        }
        return new TextParamHandler( $filename );
    }

    abstract function write();
    abstract function read();
}

class XmlParamHandler extends ParamHandler {

    function write() {
        $fh = $this->openSource("w");
        fputs( $fh, "
" );
        foreach ( $this->params as $key=>$val ) {
            fputs( $fh, "	
" );
            fputs( $fh, "		$key
" );
            fputs( $fh, "		$val
" );
            fputs( $fh, "	
" );
        }
        fputs( $fh, "
" );
        fclose( $fh );
        return true;
    }

    function read() {
        $el = @simplexml_load_file( $this->source ); 
        if ( empty( $el ) ) { 
            throw new Exception( "could not parse $this->source" );
        } 
        foreach ( $el->param as $param ) {
            $this->params["$param->key"] = "$param->val";
        }
        return true;
    } 

}

class TextParamHandler extends ParamHandler {

    function write() {
        $fh = $this->openSource("w");
        foreach ( $this->params as $key=>$val ) {
            fputs( $fh, "$key:$val
" );
        }
        fclose( $fh );
        return true;
    }

    function read() {
        $lines = file( $this->source );
        foreach ( $lines as $line ) {
            $line = trim( $line );
            list( $key, $val ) = explode( ":", $line );
            $this->params[$key]=$val;
        }
        return true;
    } 

}

//$file = "./texttest.xml"; 
$file = "./texttest.txt"; 
$test = ParamHandler::getInstance( $file );
$test->addParam("key1", "val1" );
$test->addParam("key2", "val2" );
$test->addParam("key3", "val3" );
$test->write();

$test = ParamHandler::getInstance( $file );
$test->read();

$arr = $test->getAllParams();
print_r( $arr );
本文為作者自己讀書總結(jié)的文章,由于作者的水平限制,難免會(huì)有錯(cuò)誤,歡迎大家指正,感激不盡。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/30162.html

相關(guān)文章

  • 《JavaScript設(shè)計(jì)模式開發(fā)實(shí)踐》 —— &lt;閱讀小札·一&gt;

    摘要:閱讀小札一閱讀前自大學(xué)課上,就開始接觸設(shè)計(jì)模式,但對(duì)設(shè)計(jì)模式卻鮮有研究與實(shí)踐。第二部分是核心部分,由淺到深講解個(gè)設(shè)計(jì)模式。設(shè)計(jì)模式遵循的原則所有設(shè)計(jì)模式罪訓(xùn)的一條原則就是找出程序中變化的地方,并將變化封裝起來。 閱讀小札 · 閱讀前 自大學(xué)Java課上,就開始接觸設(shè)計(jì)模式,但對(duì)設(shè)計(jì)模式卻鮮有研究與實(shí)踐。最近向公司反映和游說技術(shù)提升,得以獲得公司提供購書機(jī)會(huì),借此認(rèn)真學(xué)習(xí)前端學(xué)習(xí)之路的...

    Yangder 評(píng)論0 收藏0
  • Python超細(xì)膩研究面向對(duì)象設(shè)計(jì)

      面向?qū)ο笤O(shè)計(jì)是一類編程方式,此編程方式的落地式需要使用類和目標(biāo)來達(dá)到,因此,面向?qū)ο笤O(shè)計(jì)本身就是對(duì)類和目標(biāo)的應(yīng)用,今日給大家介紹一下python面向?qū)ο笤O(shè)計(jì)開發(fā)設(shè)計(jì)及本質(zhì)特征,感興趣的小伙伴一起了解一下吧  序言  面向?qū)ο笤O(shè)計(jì)對(duì)新手而言不難理解但無法運(yùn)用,盡管我們給大家匯總過面向?qū)ο髴?zhàn)略部署方式(定義類、創(chuàng)建對(duì)象、給目標(biāo)發(fā)信息),可是看似簡單其實(shí)不簡單。大量程序編寫訓(xùn)練與閱讀高質(zhì)量的編碼有可...

    89542767 評(píng)論0 收藏0
  • 初探面向對(duì)象編程之oop設(shè)計(jì)模式

    摘要:為什么要采用面向?qū)ο缶幊探鉀Q問題更容易設(shè)計(jì)計(jì)算機(jī)程序就是為了解決人類的問題。面向?qū)ο缶幊绦枰獙?duì)業(yè)務(wù)及代碼的架構(gòu)是有一定的要求的。 1. 編程方式 我們目前的編程方式大體可以有以下三種編程方式: 順序編程 過程式編程 面向?qū)ο缶幊? 在講面向?qū)ο缶幊虝r(shí)先講一下什么是順序編程,什么是過程式編程,什么是面向?qū)ο缶幊蹋? 順序編程: 就是只用一個(gè)單線程去執(zhí)行一段代碼,執(zhí)行過程根據(jù)代碼依次從上...

    BingqiChen 評(píng)論0 收藏0
  • Python面向對(duì)象的三大特性封裝、繼承、多態(tài)

      小編寫這篇文章的主要目的,主要是來給大家介紹關(guān)于Python的一些事情,主要還是涉及到面對(duì)面對(duì)象編程的一些實(shí)例,其中,主要涉及到的內(nèi)容涵蓋封裝、繼承、多態(tài)等多種形式,就具體的形式,下面就給大家詳細(xì)解答下?! ython是一門面向?qū)ο蟮恼Z言。面向?qū)ο蠖加腥筇匦裕悍庋b、繼承、多態(tài)?! ∠旅娣謩e來說說這三大特性:  1、封裝  隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外提供公共訪問方式。在python中用...

    89542767 評(píng)論0 收藏0
  • python命令 – 解釋器、交互式、面向對(duì)象編程語言

    Python 是一種解釋型的、交互式的、面向?qū)ο蟮木幊陶Z言,它結(jié)合了非凡的功能和非常清晰的語法。Python Library Reference 記錄了內(nèi)置的和標(biāo)準(zhǔn)的類型、常量、函數(shù)和模塊。語法格式:python [參數(shù)]常用參數(shù):參數(shù) 描述-c 直接運(yùn)行 python 語句-v 會(huì)輸出每一個(gè)模塊引用信息-i 運(yùn)行完 python 腳本文件以后打開一個(gè) python 環(huán)境-m 將模塊按照腳本執(zhí)行命...

    社區(qū)管理員 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<