2013-02-27 317 views
1

我有一個reoccuring的問題,我目前解決像這樣 -PHP設計模式

進來的具有平臺腳本變量後,該平臺是從列表,如:XBOX,PS3,PC ,一個MobileApp,手機遊戲等

爲每個不同的平臺,我希望能夠做不同的事情在我的劇本,但在某些情況下,我想代碼在此刻做的非常類似的事情我做這樣的事情:

$platformArray = array(
    'ps3'=>array('displayName'=>'playstation 3','function'=>'funcPS3'), 
    'xbox'=>array('displayName'=>'Xbox','function'=>'funcXbox') 
) 
//similar amongst all platforms code on line below 
echo 'you have a :'.$platformArray[$_POST['platform']]['displayName'].' for playing  games'; 

call_user_func($platformArray[$_POST['platform']['function']); 

function funcPS3(){ 
    echo 'ps3 specific code'; 
} 

function funcXbox(){ 
    echo 'xbox specific code'; 
} 

我想在我的代碼中使用面向對象的方法,我想要t o現在我使用對象作爲數據存儲介質而不是數組,而我有時需要在代碼中提前定義屬性,但是如何使用對象執行上述操作?

+2

你看過物體是如何工作的嗎? [你有什麼嘗試](http://whathaveyoutried.com)? – UnholyRanger 2013-02-27 21:24:20

+0

耶在基本的水平我明白他們通常有私人的內部變量,你可以設置和獲取函數,我想提前設置一些,我想我可以加載變量的對象的多個實例,我想我可以參考我可以做$ {$ _ POST ['platform']} - > myclassfunc(); ?道歉沒有嘗試它我沒有得到我的設置在這裏 – arcanine 2013-02-27 21:29:10

+0

我會做一個基地「平臺」類與預定義類似的部分,然後使XBOX/PS3/PC類繼承它,並重載一些功能的平臺具體行動。 – 2013-02-27 21:33:31

回答

0

我將從一個非常天真的OO版本開始工作,到使用多態行爲並避免全局狀態的「良好」OO代碼。

1.不多態性,具有全局靜態數據

這是非常糟糕的,因爲它實際上只是在程序代碼的包裝對象。它需要一個函數映射來調用每種類型的平臺。

class Platform {  
    private static $platformArray = array(
     'ps3' => array(
      'displayName'=>'playstation 3', 
      'function'=>'funcPS3' 
     ), 
     'xbox' => array(
      'displayName'=>'Xbox', 
      'function'=>'funcXbox' 
     ) 
    ); 

    private $type; 

    public function __construct($type) { 
     if (!array_key_exists($type, self::$platformArray)) { 
      throw new Exception("Invalid Platform type $type"); 
     } 
     $this->type = $type; 
    } 

    public function printCode() { 
     // This was a question embedded within your question, you can use 
     // http://php.net/manual/en/function.call-user-func.php 
     // and pass an instance with a method name.  
     return call_user_func(array($this, self::$platformArray[$this->type])); 
    } 

    private function funcPS3(){ 
     echo 'ps3 specific code'; 
    } 

    private function funcXbox(){ 
     echo 'xbox specific code'; 
    }  
} 

$plat = new Platform($_POST['platform']); 
$plat->printCode(); 

2.多態...但它仍然使用全局數據

By creating a base class可以實現在子類的行爲,對於每一個關心創建單獨的類。這裏最大的問題是子類需要註冊一個全局註冊表。

abstract class Platform { 
    abstract protected function getCode(); 
    public function printCode() { 
     echo $this->getCode(); 
    } 

    private function __construct() {} // so only factory can instantiate it 
    private static $platformArray = array(); 

    public static function create($type) { 
     if (!array_key_exists($type, self::$platformArray)) { 
      throw new Exception("Invalid Platform type $type"); 
     } 
     return new self::$platformArray[$type]; 

    }   

    public static function addPlatform($type, $ctor) { 
     if (!is_subclass_of($ctor, 'Platform')) { 
      throw new Exception("Invalid Constructor for Platform $ctor"); 
     } 
     self::$platformArray[$type] = $ctor; 
    } 
} 

class PlatformXBox extends Platform{ 
    protected function getCode() { 
     return 'xbox specific code'; 
    } 
} 
Platform::addPlatform('xbox', 'PlatformXBox'); 

class PlatformPs3 extends Platform { 
    protected function getCode() { 
     return 'ps3 specific code'; 
    } 
} 
Platform::addPlatform('ps3', 'PlatformPs3'); 

$plat = Platform::create($_POST['platform']); 
$plat->printCode(); 

3.多態,沒有全球性的數據

By putting your code into a namespace,您避免在基類的靜態代碼,避免映射後的參數的危險直接進入類。

namespace platform { 

interface IPlatform { 
    public function getDisplayName(); 
    public function getCode(); 
} 

class PlatformFactory { 
    static public function create($platformType) {   
     $className = "\\platform\\$platformType"; 
     if (!is_subclass_of($className, "\\platform\\IPlatform")){ 
      return null; 
     } 
     return new $className; 
    } 
} 

class Xbox implements IPlatform { 
    public function getDisplayName(){ 
     return 'xbox'; 
    } 
    public function getCode(){ 
     return 'xbox code'; 
    } 
} 

class Ps3 implements IPlatform { 
    public function getDisplayName(){ 
     return 'ps3'; 
    } 
    public function getCode(){ 
     return 'ps3 code'; 
    } 
} 

} 

現在你可以使用這些類像下面

$platform = platform\PlatformFactory::create('xbox'); 
echo $platform->getCode() ."\n" ; 

$platform2 = platform\PlatformFactory::create('ps3'); 
echo $platform2->getDisplayName()."\n"; 

$noPlatform = platform\PlatformFactory::create('dontexist'); 
if ($noPlatform) { 
    echo "This is bad, plaftorm 'dontexist' shouldn't have been created"; 
} else { 
    echo "Platform 'dontexist' doesn't exist"; 
} 
+0

@tereško我解釋了這種方法的問題。從本質上講,您需要將帖子參數映射到通過讓代碼易受攻擊而實現的不同類型的類。 – 2013-02-28 17:52:44

+0

@tereško接受了您的建議並改進了答案,請讓我知道任何建議的解決方案中存在的問題 – 2013-02-28 20:26:09

0

您可能希望創建一個類叫做平臺和類的每個平臺的不同方法中:

class platforms { 
    //Create your variables here, also called properties. 
    public $displayName; 

    //Create a function, also called a method for each platform you intent to use. 
    public function xboxPlatform(){ 
     //Code comes here what you want to do. 
    } 
} 

希望這可以幫助。

+0

這並沒有真正解決這個問題。你將如何調用基於POST變量的方法? – 2013-02-27 21:40:47

+0

我有一個全功能的教程使用OOP和PDO給你,如果你想看看: [link] https://docs.google.com/file/d/0B0fx_EGx3tG_SGFwcmZDMlJQbFE/edit?usp=sharing – Willem 2013-02-27 21:49:08

+0

True答案1是更好的選擇。 – Willem 2013-02-27 21:53:53

4

我會建議你首先理解多態性。 This lecture應該是個好的開始。

當你試圖創建行爲,基於某些標誌,你應該實現兩個類具有相同的接口:

class Xbox 
{ 
    private $displayName = 'XBox 360'; 

    public function identify() 
    { 
     // Xbox-specific stuff 
     return ':::::::::::'. $this->displayName; 
    } 
} 

class PS3 
{ 

    private $displayName = 'Playstation 3'; 

    public function identify() 
    { 
     // playstation-specific stuff 
     return '+++'. $this->displayName . '+++'; 
    } 
} 

這兩個類有法同名,會做不同的事情;

$platform = $_POST['platform']; 
// classes in PHP are case-insensitive 
// expected values would be: xbox, Xbox, ps3, pS3 
if (!class_exists($platform)) 
{ 
    echo "Platform '{$platform}' is not supported"; 
    exit; 
    // since continuing at this point would cause a fatal error, 
    // better to simply exit 
} 

$object = new $platform; 
echo $object->identify(); 

基本上,在這種情況下,你真的不在乎,你正在使用哪種類型的平臺。所有你需要知道的是它們都有相同的公共接口。這被稱爲「多態行爲」。

+0

POST類參數映射是一個很糟糕的漏洞。這就是爲什麼你需要一個允許參數的註冊表,而不是讓用戶在系統中實例化任何類。這是我在回答時的最初想法,但我不想提出一個脆弱的方法。 – 2013-02-28 17:48:19

+0

@JuanMendes,其實這個「漏洞」可以通過簡單的路由機制來處理。並將類限制到特定的命名空間。 SO中的答案永遠不會被視爲「生產閱讀代碼」。 OP要求瞭解OOP,因此,您選擇了一個倡導程序代碼的例子,而不是提供一個好的面向對象的例子(但其中有一個明顯且容易避免的缺陷)。 – 2013-02-28 18:37:22

+0

我同意,我也不想花時間最充分地找出答案。但自從你的評論,決定改善答案,以避免像你這樣的人假設我不知道OOP :)。不可能像這樣在一篇文章中講授OOP,但我希望我發佈在更新後的答案中的步驟對OP很有幫助,因爲它們逐漸從一種天真的解釋轉變爲一種很好的解釋(根據您的想法加上一個明確的界面)並解釋原因。我喜歡https://www.youtube.com/watch?v=-FRm3VPhseI鏈接。我深信依賴注入並避免全局狀態。 – 2013-02-28 20:24:17