这段代码太脆了吗?

Ste*_*hen 5 php string strategy-pattern

我需要创建一个策略模式,用户从二十或三十个唯一策略对象的列表中选择四个策略.随着项目的成熟,策略列表将会扩展,用户可以随时更改所选策略.

我打算将他们选择的策略名称存储为字符串,然后使用类似这样的方法来加载与他们选择的字符串相对应的策略类.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图避免一个大的switch语句.我担心的是,这似乎有点儿Stringly Typed.有没有更好的方法来实现这个目标而不使用条件或大型switch语句?

BTW:用户在选择四种策略时不输入字符串.我需要维护一个字符串列表,以便在选择框中向用户显示,并在添加新策略对象时将新的字符串添加到列表中.

解释
ircmaxell表达了一些关于我正在尝试做什么的混淆.在上面的示例中,用户从列表中选择了四个策略,并将它们作为字符串数组传递给StrategyManager构造函数.创建相应的策略对象并将其存储在内部数组中,$this->selectedStrategies

"第一","第二","第三"和"第四"是用于四种不同选定策略的内部阵列的数组键.在构建StrategyManager对象之后,应用程序execute在整个过程的生命周期中的各个时刻使用四种策略的方法.

因此,简而言之......每次应用程序需要执行策略编号"one"的方法时,它都会这样做,并且结果会有所不同,具体取决于用户为策略"one"选择的策略

irc*_*ell 1

根据您的评论和更新,我认为这段代码不太脆弱。如果您更改策略类型(do_one、do_two 等)的调用链或添加策略,维护将会更加困难。我建议使用抽象工厂来创建“策略”。然后,在需要策略的代码中,获取策略对象本身......

我更喜欢这种方法的原因有两个。首先,它只根据需要创建策略,因此您不会构建不需要的对象。其次,它封装了用户的选择,因为这是唯一需要查找它的地方(您可以使用依赖项注入来构建它,但您也需要其他地方来管理构建)。

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,像这样使用:

$strategy = $factory->getSomeStrategyName();
$strategy->execute();
Run Code Online (Sandbox Code Playgroud)

甚至改变:

$factory->getSomeStrategyName()->execute();
Run Code Online (Sandbox Code Playgroud)

或者没有魔法方法:

$factory->getStrategy('strategyName')->execute();
Run Code Online (Sandbox Code Playgroud)