面向物件與面向過程的區別
面向物件設計和傳統的程序式程式設計有什麼區別呢?程序式程式設計表現為一系列命令和方法的連續呼叫。這種自頂向下的控制方式導致了重複和相互依賴的程式碼遍佈於整個專案,不利於管理和維護程式碼。而面向物件程式設計則將職責從客戶端程式碼中移到專門的物件中,儘量間減少相互依賴。
下面舉個例子說明兩者的區別。
假設我們要建立一個用於讀寫配置檔案的工具。例子中忽略了具體的功能實現。
我們先按過程式方式中解決這個問題。
只需要兩個函式:
function readParams( $sourceFile){
$prams = array();
// $sourceFile 中讀取文字引數
return $prams;
}
function writeParams( $params, $sourceFile){
//寫入文字引數到$sourceFile
}
函式定義完了,下面就是呼叫了:
$file = "./param.txt";
$array['key1'] = 'val1';
$array['key2'] = 'val2';
$array['key3'] = 'val3';
writeParams($array,$file);
$output = readParams($file);
print_r($output);
到此過程式開發一個讀寫檔案的工具完成了,看起來程式碼寫的挺緊湊的,沒什麼毛病。然而,現在我們被告知這個工具需要支援讀寫如下格式的XML檔案:
<params>
<param>
<key>my key</key>
<val>my val</val>
</param>
</params>
剛接到這個改變的時候可能會想,這個簡單,在函式里加個判斷不好了,如果字尾為.xml,則從xml檔案中讀取,如果是.txt結尾,則從文字檔案中讀取。你可能會這樣設計:
function readParams( $source){
$params = array();
if( preg_match( "/\.xml$/i" , $source)){
// 從$source中讀取xml引數
} else {
// 從$source中讀取文字引數
}
return $params;
}
function writeParams( $params, $source){
if( preg_match( "/\.xml$/i", $source)){
// 寫入XML引數到$source
} else {
// 寫入文字引數到$source
}
}
上面的兩個函式中都要檢測檔案的副檔名,這就是面向過程不好的地方,會有很多重複的程式碼,Don’t Repeat Yourself是軟體設計中很重要的一點。
所以我們現在用類來處理相同的問題,首先,建立一個抽象的基類來定義型別藉口:
abstract class ParamHandler {
protected $source;
protected $params = array();
function __construce( $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()方法來允許使用者增加引數帶protected屬性$params,getAllParams()則用於訪問該屬性,獲得$params的值。
我們還建立了靜態的getInstance()方法來檢測檔案的副檔名,並根據副檔名返回特定的子類。最重要的是,我們定義了兩個抽象方法read()和write(),確保ParamHandler類的任何子類都支援這個藉口。
現在,我們定義多個子類。
class XmlParamHandler extends ParamHandler{
function write(){
// 寫入XML檔案
// 使用$this->params
}
function read(){
//讀取XML檔案內容
//並賦值給$this->params
}
}
class TextParamHander extends ParamsHander{
function write(){
//寫入文字檔案
//使用$this->params
}
function read(){
//讀取文字檔案內容
//並賦值給$this->params
}
}
這些類簡單地提供了write()和read()方法的實現。每個類都將很土適當的檔案格式進行讀寫。
客戶端程式碼將完全自動地根據副檔名來寫入資料到文字和XML格式的檔案:
$text = ParamHander::getInstance("./params.xml");
$text->addParam("key1","val1");
$text->addParam("key2","val2");
$text->addParam("key3","val3");
$text->write(); //寫入XML格式中
我們還可以從兩種檔案格式中讀取:
$text = ParamHander::getInstance("./params.txt");
$text->read(); //從文字格式中讀取
看完上面這個例子,是不是用面向物件的方式處理問題會更好呢?