关于命令模式(PHP)的问题 [英] Questions about Command Pattern (PHP)

查看:93
本文介绍了关于命令模式(PHP)的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读完之后,我在PHP中做了一个简约的Command Pattern示例。我有几个问题...

i did up a minimalistic Command Pattern example in PHP after reading up about it. i have a few questions ...

我想知道我做的是对吗?或者可能太小,从而减少命令模式的点

i'll like to know if what i did is right? or maybe too minimal, thus reducing the point of the command pattern

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 class?

i am wondering if there is any difference from simply putting this LoginCommand into a simple function say in the Users class?

如果 LoginCommand 更适合于一个类,如果它是一个静态类,它不会更好我可以简单地调用 LoginCommand :: execute() vs需要设定对象1?

if LoginCommand is better fit for a class, won't it be better if it were a static class so i can simply call LoginCommand::execute() vs needing to instanciate an object 1st?

推荐答案

命令模式的一点是能够将不同的功能隔离成一个对象(命令),因此它可以重复使用在多个其他对象(指挥官)上。通常,指挥官也将接收器传给命令,例如。该命令所针对的对象。例如:

The point of the Command Pattern is being able to isolate distinct functionality into an object (the command), so it can be reused across multiple other objects (the commanders). Usually, the Commander also passes a Receiver to the Command, e.g. an object that the command is targeted at. For instance:

$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是Commander。汽车是接收器,程序是实际的命令。当然,我可以在CarWash中有一个方法doStandardWash(),并且在CarWash中使每个命令都是一个方法,但是这种方法是不太可扩展的。每当我想添加新程序时,我都必须添加一个新的方法和命令。使用命令模式,我可以简单地传入新的命令(认为回调)并轻松创建新的组合:

In the above example, CarWash is the Commander. The Car is the Receiver and the programme are the actual Commands. Of course I could have had a method doStandardWash() in CarWash and made each command a method in CarWash, but that is less extensible. I would have to add a new method and command whenever I wanted to add new programmes. With the command pattern, I can simply pass in new Commands (think Callback) and create new combinations easily:

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

当然,您也可以使用PHP的关闭或函子,但是让我们坚持使用OOP例。命令派上用场的另一件事就是当您有多个Commander需要Command功能时,例如

Of course, you could use PHP's closures or functors for this too, but let's stick to OOP for this example. Another thing where the Commands come in handy, is when you have more than one Commander that needs the Command functionality, e.g.

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

如果我们将洗涤逻辑硬编码到CarWash中,我们现在必须复制所有代码多德。而且,由于Dude可以做许多事情(因为他是人类),他可以做的任务列表将导致一个可怕的长期课程。

If we had hardcoded the washing logic into the CarWash, we would now have to duplicate all code in the Dude. And since a Dude can do many things (because he is human), the list of tasks he can do, will result in a terrible long class.

通常,指挥官本身也是一个命令,所以你可以创建一个命令复合并将它们堆叠成树。命令通常也提供一个撤消方法。

Often, the Commander itself is also a Command, so you can create a Composite of Commands and stack them into a tree. Commands often provide an Undo method as well.

现在,回顾一下你的LoginCommand,我会说这样做并不太有意义。你没有Command对象(它是全局范围),你的Command没有Receiver。而是返回到Commander(使全局范围为Receiver)。所以你的命令在接收器上没有真正的操作。这也不太可能,您将需要抽象到一个命令,当进行登录只是在一个地方完成。在这种情况下,我同意LoginCommand更好地放置在身份验证适配器中,也许使用策略模式:

Now, looking back at your LoginCommand, I'd say it doesn't make much sense to do it this way. You have no Command object (it's the global scope) and your Command has no Receiver. Instead it returns to the Commander (which makes the global scope the Receiver). So your Command does not really operate on the Receiver. It is also unlikely, that you will need the abstraction into an Command, when doing the login is only ever done in one place. In this case, I'd agree the LoginCommand is better placed into an Authentication adapter, maybe with a Strategy pattern:

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';
};

你可以做一些更命令般的命令:

You could do it somewhat more Command-like:

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

当然,您可以向用户添加验证方法,但是您必须将数据库适配器设置为用户才能进行身份验证,例如

You could add the authenticate method to the User of course, but then you would have to set the Database adapter to the User in order to do the authentication, e.g.

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

这也是可能的,但是个人来说,我不明白为什么用户应该有一个验证适配器。听起来不像用户应该有的东西。用户具有认证适配器所需的凭据,但不具有适配器本身。将适配器传递给用户的认证方法将是一个选项:

That would be possible too, but personally, I don't see why a User should have an Authentication adapter. It doesn't sound like something a user should have. A user has the Credentials required by an Authentication adapter, but the not the adapter itself. Passing the adapter to the user's authenticate method would be an option though:

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

再次,如果您使用ActiveRecord,那么您的用户将会了解数据库,然后您可以简单地转储所有上述内容,并将完整的验证码写入用户。

Then again, if you are using ActiveRecord, then your user will know about the database anyway and then you could simply dump all the above and write the entire authenticatation code into the user.

如您所见,它归结为如何设置应用程序。这使我们得出最重要的一点:设计模式为常见问题提供解决方案,让我们可以谈论这些问题,而无需首先定义大量的术语。这很酷,但是通常你必须修改模式才能解决你的具体问题。您可以花几个小时的时间来理解建筑和使用哪些模式,并且您不会编写单个代码。如果一个模式对于建议的定义是100%真的,不要太多考虑。确保您的问题得到解决。

As you can see, it boils down to how you are setting up your application. And that brings us to to the most important point: Design Patterns offer solutions to common problems and they let us allow to speak about these without having to define tons of terms first. That's cool, but often, you will have to modify the patterns to make them solve your concrete problem. You can spend hours theorizing about architecture and which patterns to use and you wont have written a single code. Don't think too much about if a pattern is 100% true to the suggested definition. Make sure your problem is solved.

这篇关于关于命令模式(PHP)的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆