哪种编程设计模式适合这个项目?

时间:2015-07-19 08:43:12

标签: php oop laravel design-patterns

您好我正在寻找选择编程设计模式以适合我当前项目的一些指导。

我几个月来一直试图找到一个很好的项目来开始正确使用模式,而我刚刚开始的一个小项目似乎提供了一个完美的学习平台。

基本上我正在创建一个响应用户命令的Telegram Bot。这不是我遇到问题的部分,它是如何最好地构建我的代码,以便添加新命令是干净和结构良好的。

我不需要任何人为我编写任何代码,但是我可以实现适合的设计模式吗?

这是我目前正在做的puesudo(BTW我正在使用Laravel)代码:

//routes.php

  Route::post('inbound', ['uses' => 'inboundController@marshall']);



 //inboundController.php

   public function marshall($inboundMessage){

    //Extract the command from the inbound message eg "start"
    $command = extractfromtext($text);

    //Get the user id from the person who sent the message
    $userID = extractIdfromtext($text);

    //Compare the command in a switch statement

    switch ($command){

    case (start):
        return $result = new commandStart($userID)->fire();
        break;
    case (demo):
        return $result = new commandDemo($userID)->fire();
        break;
    case (another):
        return $result = new commandAnother($userID)->fire();
        break;
    default:
       break;

    }

   } 


//Each command has it's own class:
//Class commandStart

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

   publin fuction fire(){

     //send a picture to the userID

   }



//Class commandDemo

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

   publin fuction fire(){

     //send a message to the userID

   }



//Class commandAnother

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

   publin fuction fire(){

     //send a video to the userID

   }

这很好用,但我觉得

  • 我重复了很多代码(不好)
  • 添加新命令意味着连续编辑“入站类”文件。我认为这打破了SOLID中的开放封闭原则。
  • switch语句对我有“代码味道”。

我对不同类型的模式的所有名称感到困惑。有人会告诉我,哪一个适合这种情况?我很高兴去研究它以及它是如何实现的,但是我不想在追逐鹅的时候选择一个不合适的,因为我不知道更好!

谢谢。

编辑:在我试图使问题变得通用的时候,我似乎太过迟钝了。我已经在使用Larvel的MVC了。这不是问题我认为 - 我想知道哪种设计模式可以让我轻松,干净地添加更多命令 - 希望不必使用switch语句。

在阅读了一些回复后,我想我已经开始了解该怎么做了。出于兴趣 - 是在实际设计模式下建议的结构还是仅仅是良好的结构化代码?

3 个答案:

答案 0 :(得分:2)

除了arkascha之外,我还建议你为命令使用抽象类

abstract class Command {

    public function __construct( $params ){
        // do some common things with $params
        $this->do_command();
    }

    protected function do_command(){
         // empty function which will be overwritten by child classes
    }

}

你的孩子班就像

class FooCommand extends Command {

    public function __construct( $params ){
        parent::__construct( $params );
        // do something as well
    }

    // can be public
    public function do_command(){
         echo __CLASS__, '::FOO';
    }
}

class BarCommand extends Command {

    // or without __constructor as mentioned by scrowler if you dont
    // need to do additional coding with __contructor params

    // can be protected
    protected function do_command(){
         echo __CLASS__, '::BAR';
    }
}

class BazCommand extends Command {

    public function __construct( $params ){
        parent::__construct( $params );
        // do something as well
    }

    // it cannot be private
    private function do_command(){
         echo __CLASS__, '::BAZ';
    }
}

答案 1 :(得分:2)

请查看命令设计模式。您也可以使用之前建议的抽象工厂模式来实例化要执行的命令。

详细说明我的答案。 让我们的客户端类调用入站控制器。控制器的责任是捕获请求并将其路由到正确的操作,在这种情况下触发命令。 但是如果你看一下代码,控制器实际上是决定在它接收的某个输入中实例化什么类型的命令。如果由于某种原因命令类的构造函数发生更改,那么您还必须更改入站控制器类中的代码,因为它现在还负责实例化要执行的命令对象。 如果您实现了一个抽象工厂并注入到您的控制器中,那么您将所需的输入传递给您的工厂,以决定应该实例化哪个命令并将其传递给控制器​​。控制器只是触发它从工厂收到的命令,而不必担心命令是如何实例化的或命令的类型。控制器获得执行命令的请求,将命令的实例化委托给工厂,并且一旦命令由工厂交给控制器,它就被执行。 单一责任原则是最好的。抽象工厂负责实例化命令。控制器负责处理请求,在这种情况下,执行工厂返回的命令。

通过查看代码,人们已经可以看到他正在以某种方式使用Command设计模式。以下是维基百科的定义:Command design pattern

答案 2 :(得分:0)

您在代码中实现的是MVC路由器。目前你硬编码路线。相反,您还可以依靠自动加载为控制器实例化选择正确的类。如果该类不存在则回退将使事情变得健壮。两个优点:

  • 易于扩展,您只需在由命名约定命名的文件中添加控制器类

  • 添加其他控制器时,您根本不需要触摸路由器

你会在互联网上找到很多关于这方面的例子。自动加载功能也有详细记录。

玩得开心!