dongqiaogouk86049 2013-02-27 21:20
浏览 35
已采纳

PHP设计模式

I have a reoccuring problem that I am currently tackling like so -

a POST variable coming in to the script which has a platform, the platform is from a list such as: xbox,ps3,pc,mobileapp,mobilegame etc

for each different platform I want to be able to do something different in my script but in some cases I want code to do very similar things at the moment I do something like this:

$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';
 }

I want to move towards a OOP approach in my code, I want to use objects as my data storage medium rather than arrays as I'm doing now, but I do sometimes need to define attributes in the code ahead of time, how could I do the above but with objects?

  • 写回答

3条回答 默认 最新

  • dsf487787 2013-02-27 21:35
    关注

    I'm going to work from a very naive OO version, to what is considered "good" OO code, using polymorphic behavior and avoiding global state.

    1. Not polymorphic and has global static data

    This is pretty bad because it is really just a wrapper object over procedural code. It needs a map of functions to call for each type of platform.

    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. Polymorphic... but it still uses global data

    By creating a base class you can implement behavior in subclasses, creating separate class for each concern. The big problem here is that subclasses need to register with a global registry.

    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. Polymorphic, no global data

    By putting your code into a namespace, you avoid the static code in the base class and avoid the dangers of mapping post parameters directly into classes.

    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';   
        }
    }
    
    }
    

    Now you can use those classes like the following

    $platform = platform\PlatformFactory::create('xbox');
    echo $platform->getCode() ."
    " ;
    
    $platform2 = platform\PlatformFactory::create('ps3');
    echo $platform2->getDisplayName()."
    ";
    
    $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";
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?