2013-02-27 63 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