2013-02-27 5 views
1

У меня есть reoccuring проблема, что я в настоящее время решения, как так -PHP Design Pattern

переменная POST, поступающие в скрипт, который имеет платформу, платформа из списка, такие как: Xbox, PS3, ПК , 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'; 
} 

Я хочу перейти к подходу OOP в своем коде, я хочу t o использовать объекты как свой носитель хранения данных, а не массивы, как я делаю сейчас, но иногда мне нужно заранее определить атрибуты кода, как я могу сделать это, но с объектами?

+2

Вы изучили, как работают объекты? [Что вы пробовали] (http://whathaveyoutried.com)? – UnholyRanger

+0

Да, на базовом уровне Я понимаю, что у них обычно есть частные внутренние переменные, которые вы можете установить и получить с помощью функций, я хочу установить некоторое время раньше, я полагаю, я мог бы загружать несколько экземпляров объектов с помощью переменных, я думаю, я мог бы ссылаться к объекту с помощью $ {$ _ POST ['platform']} могу ли я делать такие вещи, как $ {$ _ POST ['platform']} -> myclassfunc(); ? извинения за то, что не пытались это сделать. У меня нет моей настройки здесь. – arcanine

+0

Я бы сделал базовый «платформенный» класс с предопределенными аналогичными частями, затем создавал классы XBOX/PS3/PC, которые наследуют его и перегружают некоторые функции с помощью платформы -специфические действия. –

ответ

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 Я объяснил проблемы с этим подходом. По сути, вам нужно сопоставить параметры сообщений с различными типами классов, которые вы достигли, сделав ваш код уязвимым. –

+0

@ tereško Принял ваш совет и улучшил ответ, сообщите мне о любых проблемах с предлагаемым решением. –

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? –

+0

У меня есть полностью функциональный учебник с использованием OOP и PDO для вас, если вы хотите взглянуть на это: [link] https://docs.google.com/file/d/0B0fx_EGx3tG_SGFwcmZDMlJQbFE/edit?usp=sharing – Willem

+0

True Ответ 1 - лучший вариант. – Willem

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 Отображение параметров для классов - это плохая уязвимость. Вот почему вам нужен реестр разрешенных параметров вместо того, чтобы просто позволить пользователю создать экземпляр любого класса в системе. Это была моя первоначальная идея, когда я отвечал, но я не хотел предлагать уязвимый способ. –

+0

@JuanMendes. Фактически, «уязвимость» может быть обработана простым механизмом маршрутизации. И ограничение классов на определенное пространство имен. Ответ в SO никогда не следует воспринимать как «код чтения продукции». ОП просил понять ООП, поэтому вместо того, чтобы давать хороший объектно-ориентированный пример (но с очевидным и легко избегаемым недостатком), вы выбрали пример, который защищал процедурный код, который злоупотребляет глобальным состоянием. –

+0

Я согласен, я также не хотел тратить время на то, чтобы выработать ответ в полном объеме. Но с вашего комментария, решил улучшить ответ, чтобы избежать таких людей, как вы, предполагая, что я не знаю ООП :). Невозможно научить ООП в одном сообщении, как это, но я надеюсь, что шаги, которые я опубликовал в моем обновленном ответе, полезны для ОП, поскольку они постепенно переходят от наивного объяснения к приятному (на основе вашей идеи плюс явный интерфейс) и объясните, почему. Мне понравилась ссылка https://www.youtube.com/watch?v=-FRm3VPhseI. Я большой сторонник инъекций зависимостей и избегаю глобального состояния. –