Is this code too fragile?

I need to create a strategy template in which the user selects four strategies from a list of twenty or thirty unique strategy objects. The list of strategies will expand as the project matures, and users can change their chosen strategy at any time.

I plan to store the names of the strategies that they selected as strings, and then use a method like this to load the strategy classes corresponding to their selected strings.

class StrategyManager { // simplified for the example
    public $selectedStrategies = array();
    public function __construct($userStrategies) {
        $this->selectedStrategies = array(
            'first'  => new $userStrategies['first'],
            'second' => new $userStrategies['second'],
            'third'  => new $userStrategies['third'],
            'fourth' => new $userStrategies['fourth']
        );
    }

    public function do_first() {
        $this->selectedStrategies['first']->execute();
    }

    public function do_second() {
        $this->selectedStrategies['second']->execute();
    }

    public function do_third() {
        $this->selectedStrategies['third']->execute();
    }

    public function do_fourth() {
        $this->selectedStrategies['fourth']->execute();
    }
}

I am trying to avoid a big switch statement. It bothers me what it looks like Stringly Typed. Is there a better way to achieve this without using a conditional or large switch statement?

BTW: . , .


ircmaxell , . , StrategyManager . , $this->selectedStrategies

"", "", "" "" - . , StrategyManager , execute .

, ... , "", , , , ""

+5
3

, , . , (do_one, do_two ..), . abstract factory "". , , ...

, , . -, , , . -, , , ( , ).

class StrategyFactory {

    protected $strategies = array();

    //If you like getter syntax
    public function __call($method, $arguments) {
        $method = strtolower($method);
        if (substr($method, 0, 3) == 'get') {
            $strategy = substr($method, 3);
            return $this->getStrategy($strategy);
        }
        throw new BadMethodCallException('Unknown Method Called');
    }

    public function getStrategy($strategy) {
        if (isset($this->strategies[$strategy])) {
            return $this->strategies[$strategy];
        } elseif ($this->makeStrategy($strategy)) {
            return $this->strategies[$strategy];
        }
        throw new LogicException('Could not create requested strategy');
    }

    protected function makeStrategy($name) {
        //pick strategy from user input
        if ($strategyFound) {
            $this->strategies[$name] = new $strategy();
            return true;
        } else {
            return false;
        }
    }
}

:

$strategy = $factory->getSomeStrategyName();
$strategy->execute();

:

$factory->getSomeStrategyName()->execute();

:

$factory->getStrategy('strategyName')->execute();
+1

, , , . , . , 0,1,2,3. , , .

public function __construct() {
    $this->selectedStrategies = array(
        /* could add some default strategies */
    );
}
public function load(array $userStrategies) {
    for( $i=0; $i<3; $i++ ) {
        try {
            $rc = new ReflectionClass($userStrategies[$i]);
            if( $rc->implementsInterface('Iterator') ) {
                $this->selectedStrategies[$i] = new $userStrategies[$i];
            } else {
                throw new InvalidArgumentException('Not a Strategy');
            }
        } catch(ReflectionException $e) {
            throw new InvalidArgumentException('Not a Class');
        }
    }
}

, ,

$this->selectedStrategies[0]->execute();

..


class StrategyCollection
{
    protected $strategies;

    public function __construct() {
        $this->strategies = new SplFixedArray(4);
    }

    public function add(IStrategy $strategy) {
        $this->strategies[] = $strategy;
        return $this;
    }
}

/ . type IStrategy , , , . Reflection . SplFixedArray , Runtime Exception .


selectbox. , selectbox , , . .

+2

, : call_user_func($strategy['first']); ( ..). , , .. call_user_func(array('Strategies', $strategy['first']));. ( selectbox) get_class_methods('Strategies');, , .

, - - - -

function doStrategy($class) {
    static $selectedStrategies = array();

    if (!isset($selectedStrategies[$class])) {
        $selectedStrategies[$class] = new $class;
    }

    $Strategy = $selectedStrategies[$class];
    $Strategy->execute(); // some versions of PHP require two lines here
}

, , : P.

The epithet "Stringly Typed" is not applicable to PHP, since it is weakly typed and already internally uses strings to store characters (class and function names, variables, etc.). Thus, the type of string data is often best suited for reflection. We will not go into what this means for the language as a whole.

0
source

All Articles