Вопросы о шаблоне "команда" (PHP)

я привел в порядок минималистический пример Шаблона "команда" в PHP после чтения об этом. у меня есть несколько вопросов...

мне понравится знать, правильно ли то, что я сделал? или возможно слишком минимальный, таким образом уменьшая точку шаблона "команда"

interface ICommand {
  function execute($params);
}
class LoginCommand implements ICommand {
  function execute($params) {
    echo "Logging in : $params[user] / $params[pass] <br />";
    $user = array($params["user"], $params["pass"]);
    // faked users data
    $users = array(
      array("user1", "pass1"),
      array("user2", "pass2")
    );

    if (in_array($user, $users)) {
      return true;
    } else {
      return false;
    }
  }
}

$loginCommand = new LoginCommand();
// $tries simulate multiple user postbacks with various inputs
$tries = array(
  array("user" => "user1", "pass" => "pass1"),
  array("user" => "user2", "pass" => "pass1"),
  array("user" => "user2", "pass" => "PaSs2")
);

foreach ($tries as $params) {
  echo $loginCommand->execute($params) ? " - Login succeeded!" : " - Login FAILED!";
  echo " <br />";
}

я задаюсь вопросом, существует ли какое-либо различие от простого помещения этого LoginCommand в простую функцию говорят в Users класс?

если LoginCommand лучше подходящий для класса, не был бы он быть лучше, если бы это был статический класс, таким образом, я могу просто звонить LoginCommand::execute() по сравнению с необходимостью к instanciate 1-й объект?

9
задан Gordon 8 November 2012 в 08:18
поделиться

1 ответ

Суть шаблона команд заключается в том, что он может изолировать различные функциональные возможности в объекте (команде), поэтому его можно повторно использовать для нескольких других объектов (командиров). Обычно командир также передает приемник команде, например, объект, на который нацелена команда. Например:

$car = new Car;
echo $car->getStatus(); // Dirty as Hell
$carWash = new CarWash;
$carWash->addProgramme('standard',
                        new CarSimpleWashCommand, 
                        new CarDryCommand, 
                        new CarWaxCommand);
$carWash->wash();
echo $car->getStatus(); // Washed, Dry and Waxed

В приведенном выше примере Автомойка является командиром. Автомобиль - это приемник, а программа - это фактические команды. Конечно, я мог бы иметь метод doStandardWash() в CarWash и сделать каждую команду методом в CarWash, но это менее расширяемо. Мне пришлось бы добавлять новый метод и команду всякий раз, когда я хотел добавить новые программы. С помощью шаблона команд я могу просто передавать новые команды (например, Callback) и легко создавать новые комбинации:

$carWash->addProgramme('motorwash',
                        new CarSimpleWashCommand, 
                        new CarMotorWashCommand,
                        new CarDryCommand, 
                        new CarWaxCommand);

Конечно, вы можете использовать закрытия или функторы PHP для этого тоже,но давайте придерживаться ООП для этого примера. Еще одна вещь, где команды пригодятся, это когда у вас есть более одного командира, которому нужна функциональность command, например,

$dude = new Dude;
$dude->assignTask('washMyCarPlease', new CarSimpleWashCommand);
$dude->do('washMyCarPlease', new Car);

Если бы мы жестко запрограммировали логику стирки в CarWash, нам пришлось бы дублировать весь код в Dude. А так как Чувак может делать много вещей (потому что он человек), список задач, которые он может выполнить, приведет к ужасному длинному классу.

Часто сам Командир также является Командой, поэтому вы можете создать Состав команд и сложить их в дерево. Команды часто также предоставляют метод Undo.

Теперь, оглядываясь на ваш LoginCommand, я бы сказал, что нет особого смысла делать это таким образом. У вас нет объекта Command (это глобальная область), а у команды Нет Receiver. Вместо этого он возвращается к Командиру (что делает глобальную область Приемником). Таким образом, ваша команда на самом деле не работает на приемнике. Также маловероятно, что вам понадобится абстракция в Команду,при выполнении входа в систему делается только в одном месте. В этом случае я бы согласился, что LoginCommand лучше поместить в адаптер аутентификации, возможно, с шаблоном Strategy:

interface IAuthAdapter { public function authenticate($username, $password); } 
class DbAuth implements IAuthAdapter { /* authenticate against database */ }
class MockAuth implements IAuthAdapter { /* for UnitTesting */ }

$service = new AuthService();
$service->setAdapter(new DbAuth);
if( $service->authenticate('JohnDoe', 'thx1183') ) {
    echo 'Successfully Logged in';
};

Вы могли бы сделать это несколько более похожим на Command:

$service = new LoginCommander;
$service->setAdapter(new DbAuth);
$service->authenticate(new User('JohnDoe', 'thx1138'));
if($user->isAuthenticated()) { /* ... */}

Вы могли бы добавить метод authenticate к Пользователю, конечно, но тогда вам пришлось бы установить адаптер базы данных для Пользователя, чтобы выполнить аутентификацию, Например,

$user = new User('JohnDoe', 'thx1138', new DbAuth);
if ( $user->authenticate() ) { /* ... */ }

Это тоже возможно, но лично я не понимаю, почему пользователь должен иметь адаптер аутентификации. Это не похоже на то, что должен иметь пользователь. У пользователя есть учетные данные, необходимые адаптеру проверки подлинности, но не сам адаптер. Передача адаптера методу authenticate пользователя была бы вариантом:

$user = new User('JohnDoe', 'thx1138');
if ( $user->authenticateAgainst($someAuthAdapter) ) { /* ... */ }

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

Как видите,все сводится к тому, как вы настраиваете приложение. И это подводит нас к самому важному моменту: шаблоны проектирования предлагают решения общих проблем, и они позволяют нам говорить об этом без необходимости сначала определять тонны терминов. Это круто, но часто вам придется модифицировать шаблоны, чтобы они решили вашу конкретную проблему. Вы можете часами теоретизировать об архитектуре и о том, какие шаблоны использовать, и вы не написать ни одного кода. Не думайте слишком много о том, соответствует ли шаблон на 100% предложенного определения. Убедитесь, что ваша проблема решена.

34
ответ дан 4 December 2019 в 06:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: