Как перенести шаблон команды java с помощью runnable на PHP 7.4? - PullRequest
7 голосов
/ 09 марта 2020

В целях изучения я пытаюсь перевести этот Java пример шаблона команды на PHP:

https://codereview.stackexchange.com/questions/52110/command-pattern-implementation

UML diagram

Как прокомментировал @simon , используя оператор ссылки на метод, можно было бы немного модернизировать код:

class MyCommand implements Order {
    private final Runnable action;

    public MyCommand(Runnable action) {
         this.action = action;
    }

    @Override
    public void execute() {
         action.run();
    }
}

И тогда вы могли бы создавать такие команды, как это:

MyCommand bsc = new MyCommand(stock::buy);
MyCommand ssc = new MyCommand(stock::sell);

Моя текущая реализация PHP находится здесь: https://3v4l.org/iIHn9

Итак, каков наилучший подход для реализации класса MyCommand в PHP

Ответы [ 3 ]

4 голосов
/ 11 марта 2020

В PHP вы можете добиться того же, используя call_user_func, что аналогично справочному методу в Java.

<?php

namespace StockCommandNS;

//Command interface
interface Order {
    public function execute();
}

//Receiver class
class StockTrade {

    public function buy() {
        print("You want to buy stocks\n");
    }

    public function sell() {
        print("You want to sell stocks\n");
    }
}

//Invoker class
class Agent {

    public function placeOrder(Order $order) {
        $order->execute($order);
    }
}

//ConcreteCommand Class
class GenericOrder implements Order {

    private $action;

    public function __construct($action) {
        $this->action = $action;
    }

    public function execute() {
        call_user_func($this->action);
    }
}

$stock = new StockTrade();
$bsc = new GenericOrder([$stock, 'buy']);
$ssc = new GenericOrder([$stock, 'sell']);
$agent = new Agent();
$agent->placeOrder($bsc); // Buy Shares
$agent->placeOrder($ssc); // Sell Shares

Выход для 7.2.0 - 7.4. 3

You want to buy stocks
You want to sell stocks

Выполнить PHP код: https://3v4l.org/fWo20

Еще один менее чистый вариант - использовать функцию переменной.

class GenericOrder implements Order {

    private $stock;
    private $action;

    public function __construct($stock, $action) {
        $this->stock = $stock;
        $this->action = $action;
    }

    public function execute() {
        $method = $this->action;
        $this->stock->$method();
    }
}

$bsc = new GenericOrder($stock, 'buy');
$ssc = new GenericOrder($stock, 'sell');

Я не уверен, что подход со ссылками на метод лучше во всех случаях. Как правило, в каждом конкретном случае следует всегда учитывать, когда использовать ссылки на метод или анонимная функция является шаблоном Command.

4 голосов
/ 12 марта 2020

Как уже упоминал Евгений, вы можете использовать call_user_fun c () .

Поскольку существует множество способов решения этой проблемы, я добавил свои решения к вашему вопросу. Вы также можете создать объект callable, добавив метод __ invoke внутри класса. Также возможно вернуть функцию callable. Я добавил всего 3 примера для этого.

Это моя версия вашего MyCommand класса в java, которая используется для всех 3 примеров.

class MyCommand implements Order
{
    private $action;

    public function __construct(callable $action)
    {
        $this->action = $action;
    }

    public function execute()
    {
        // Option 1) use call_user_function
        call_user_func($this->action);

        // Option 2) define it as a variable and call it by adding `()`
        //$action = $this->action;
        //$action();
    }
}

Пример 1) Вызываемая функция (https://3v4l.org/FVTEK)

class Stock
{
    public function buy(): callable
    {
        return function () {
            echo "You want to buy stocks via callable function" . PHP_EOL;
        };
    }

    public function sell(): callable
    {
        return function () {
            echo "You want to sell stocks via callable function" . PHP_EOL;
        };
    }
}

$stock = new Stock();
$bsc = new MyCommand($stock->buy());
$ssc = new MyCommand($stock->sell());

$bsc->execute();
$ssc->execute();

Пример 2) Вызываемый класс (https://3v4l.org/BrKjv)

class StockBuy
{
    public function __invoke()
    {
        echo "You want to buy stocks via __invoke()" . PHP_EOL;
    }
}

class StockSell
{
    public function __invoke()
    {
        echo "You want to sell stocks __invoke()" . PHP_EOL;
    }
}

$bsc = new MyCommand(new StockBuy());
$ssc = new MyCommand(new StockSell());

$bsc->execute();
$ssc->execute();

Пример 3) Stati c функции-члены, которые возвращают вызываемые. Просто пример, чтобы быть ближе к java (https://3v4l.org/PKk4B)

class Stock
{
    static public function buy(): callable
    {
        return function () {
            echo "You want to buy stocks via callable function" . PHP_EOL;
        };

        // or as callable object
        // return new StockBuy();
    }

    static public function sell(): callable
    {
        return function () {
            echo "You want to sell stocks via callable function" . PHP_EOL;
        };

        // or as callable object
        // return new StockSell();
    }
}

$bsc = new MyCommand(Stock::buy());
$ssc = new MyCommand(Stock::sell());
$bsc->execute();
$ssc->execute();

Пожалуйста, дайте мне знать, если у вас есть какие-либо дополнительные вопросы.

0 голосов
/ 11 марта 2020

Вот некоторые ссылки относительно шаблонов проектирования PHP:

https://designpatternsphp.readthedocs.io/en/latest/README.html https://phptherightway.com/#design_patterns

...