Reputation: 307
Hello I'm looking for some guidance in choosing a programming design pattern to fit my current project.
I'm been trying for months to find a nice project to start using patterns properly and a little project I've just started seems to provide the perfect platform to learn from.
Basically I'm creating a Telegram Bot that will respond to users commands. That's not the part I'm having problems with, it's how best to structure my code so that adding new commands is clean and well structured.
I don't need anyone to write any code for me, but is there a design pattern I could implement that would suit?
Here's what I'm currently doing in puesudo (BTW I'm using Laravel) code:
//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
}
This works fine, but I feel that
I get very confused by all the names of the different type of patterns. Would someone advise me, which one would suit this scenario? I'm very happy to go and research about it and how it's implemented, but I don't want to go off on a goose chase and pick an unsuitable one because I don't know any better!
Thank you.
Edit: It seems in my attempt to make the problem generic I made it too obtuse. I am already using MVC with Larvel. That is not the problem I think - I would like to know which design pattern would allow me to add more commands easily and cleanly - hopefully not having to use a switch statement.
After reading some of the replies, I think I'm starting to get the idea of what to do. Out of interest - is the structure suggested below an actual design pattern or just good structured code?
Upvotes: 1
Views: 281
Reputation: 238
Please take a look at the Command design pattern. You could also use a Abstract Factory Pattern as previously suggested to instantiate the command to be executed.
To elaborate a little more on my answer. Lets call the inbound controller our client class. The responsability of a controller is to capture a request and route it to the proper action, in this case fire a command. But if you take a look at the code, the controller is actually deciding what type of command to instantiate base in some input that it's receiving. If for some reason the constructor of the command class changes, then you'll also have to change the code in your inbound controller class, as it is now also responsible from instantiating the command object to be executed. If you implement a Abstract Factory and injected to your controller, then you pass the input necessary to your factory to decide which command should be instantiated and handed to the controller. The controller just fires the command that it receives from the factory, without having to worry how the command was instantiated or what type of command it is. The controller gets a request to execute a command, delegates instantiation of the command to the factory, and once the command is handed to the controller by the factory, it is executed. Single responsibility principle at it's best. The abstract factory is responsible of instantiating the commands. The controller is responsible of handling the request, in this case, executing the command returned by the factory.
By taking a look at the code one can already see he is using somehow the Command design pattern. Here is a definition from wikipedia: Command design pattern
Upvotes: 2
Reputation: 1759
on top of what arkascha sad I would also recommend you to use an abstract class for your commands
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
}
}
and your child classes would be like
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';
}
}
Upvotes: 2
Reputation: 42885
What you implement in your code is a MVC router. Currently you hard code routes. Instead you can also rely on autoloading to pick the right class for your controller instantiation. A fallback if the class does not exist will make things robust. Two advantages:
easy to extend, you only have to add the controller class in a file named by naming conventions
you do not have to touch the router at all when you add another controller
You will find many examples about that on the internet. The autoloading feature also is well documented.
Have fun!
Upvotes: 0