Точка командного шаблона может выделять отдельные функции в объект (команду), поэтому его можно использовать повторно для нескольких других объектов (командиров). Обычно Командующий также передает Получателю команду, например. объект, на который нацелена команда. Например:
$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
В приведенном выше примере CarWash является Командиром. Автомобиль - это приемник, а программа - это настоящие команды. Конечно, у меня мог бы быть метод doStandardWash() в CarWash и каждый из них использовал метод в CarWash, но это менее расширяемо. Мне нужно было бы добавить новый метод и команду всякий раз, когда я захочу добавить новые программы. С узором команды, я могу просто перейти в новых командах (думает, обратный вызов) и создавать новые комбинации легко:
$carWash->addProgramme('motorwash',
new CarSimpleWashCommand,
new CarMotorWashCommand,
new CarDryCommand,
new CarWaxCommand);
Конечно, вы можете использовать затворы или функторы PHP для этого тоже, но давайте придерживаться ООП для этого пример. Другое дело, когда команды пригодились, - это когда у вас есть несколько Командующих, которым нужна функциональность Команды, например.
$dude = new Dude;
$dude->assignTask('washMyCarPlease', new CarSimpleWashCommand);
$dude->do('washMyCarPlease', new Car);
Если мы жёстко промывочной логики в автомойке, мы теперь придется дублировать код в Dude. И поскольку Чувак может делать много вещей (потому что он человек), список задач, которые он может сделать, приведет к ужасному длинному классу.
Часто Командир также является Командой, поэтому вы можете создавать композиты команд и складывать их в дерево. Команды часто также предоставляют метод отмены.
Теперь, оглядываясь назад на ваш LoginCommand, я бы сказал, что это не имеет смысла делать это таким образом. У вас нет объекта Command (это глобальная область), и ваша команда не имеет приемника. Вместо этого он возвращается в Commander (что делает глобальную область получателем). Таким образом, ваша команда не работает на приемнике. Также маловероятно, что вам понадобится абстракция в Команду, когда регистрация будет только когда-либо сделана в одном месте. В этом случае, я соглашаюсь LoginCommand лучше помещается в адаптер аутентификации, может быть с рисунком стратегии:
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';
};
Вы можете сделать это несколько больше команд, как:
$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% соответствует предложенному определению. Убедитесь, что ваша проблема решена.
u очень хорошо объяснил, мне нужно когда-нибудь переварить его. БЛАГОДАРЯ! –
Концепция «приемника» всегда исключена из других объяснений, которые я нашел. Я думаю, что в настоящее время мы не подчеркиваем приемник в том же блоке кода, что и подчеркиваем асинхронность. Хороший ответ даже спустя 4 года. – JoshuaDavid