DESIGN PATTERNS SAGA #7: REAL PROJECT SITUATIONS WITH COMMAND

Creating multiple methods inside only one class can bring many problems like inflexibility and difficulty maintaining code. I am sure all of us have already seen a class full of methods and different responsibilities, right? Classes like these are very difficult to understand, take a lot of time to find out what is happening in all methods and are difficult to test. Fortunately, there is a way to solve this problem – we can use the Command Pattern! The Command Pattern encapsulates its behavior in a separate class that is executed by the Invoker class.

command_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

A very common example of the Command Pattern is the Thread class that receives the Runnable interface with the command inside the run method.

public class ThreadCommandExample {

	public static void main(String[] args) {
		TaskCommand command = new TaskCommand(10, 12); 

		Thread invoker = new Thread(command);
		invoker.start();
	}

	static class TaskCommand implements Runnable {

		int num1;
		int num2;

		TaskCommand(int num1, int num2) {
			this.num1 = num1;
			this.num2 = num2;
		}

		@Override
		public void run() { //execute method
			System.out.println(num1 * num2); //receiver
		}
	}
}

1 – Command interface: This is the base of the Pattern, without this generic interface nothing happens. No secrets here, just an interface that has the execute method, nothing more.

public interface Command {

	public void execute();

}

2 – Discount class: this class contains the information to be processed. It’s a simple POJO.

public class Discount {

	private boolean eligible;
	private boolean discountApplied;

	public Discount(boolean eligible) {
		this.eligible = eligible;
	}

	public void applyDiscount() {
		discountApplied = true;
		System.out.println("Discount applied!");
	}

	// Getters and setters omitted

}

3 – Commands: These actions must be executed inside the Invoker. The ApplyDiscountCommand has the business requirements in order to apply the discount. The ApplyAllDiscountsCommand is responsible for encapsulating the ApplyDiscountCommand in order to apply all the discounts once. So, this Command receives a Discount list and invokes the applyDiscount method.

public class ApplyDiscountCommand implements Command {

	private Discount discount;

	public ApplyDiscountCommand(Discount discount) {
		this.discount = discount;
	}

	@Override
	public void execute() {
		if (discount.isEligible()) {
			discount.applyDiscount();
		}
	}

}

public class ApplyAllDiscountsCommand implements Command {

	private List<Discount> discounts;

	public ApplyAllDiscountsCommand(List<Discount> discounts) {
		this.discounts = discounts;
	}

	@Override
	public void execute() {
		discounts.forEach(e -> new ApplyDiscountCommand(e).execute());
	}

}

4 – CommandInvoker: As the name says, it’s going to invoke the Command. We are receiving the Command in the Constructor to be executed in the execute method.

public class CommandInvoker {

	private Command command;

	public CommandInvoker(Command command) {
		this.command = command;
	}

	public void execute() {
		this.command.execute();
	}

}

5 – Unit Tests: All is set to execute Unit Tests. To execute the Command, create the Discount list. Then use the CommandInvoker passing the Command in the Constructor. In the end, execute the Command!

Now, ensure the discounts were applied correctly!

public class CommandTest {

	@Test
	public void applyCommandTest() {
		List<Discount> discounts = mockDiscounts();

		ApplyAllDiscountsCommand command =
                   new ApplyAllDiscountsCommand(discounts);

		CommandInvoker invoker = new CommandInvoker(command);
		invoker.execute();

		Assert.assertTrue(discounts.get(0).isDiscountApplied());
		Assert.assertFalse(discounts.get(1).isDiscountApplied());
		Assert.assertTrue(discounts.get(2).isDiscountApplied());
		Assert.assertFalse(discounts.get(3).isDiscountApplied());
	}

	private List<Discount> mockDiscounts() {
		return Arrays.asList(new Discount(true),
                     new Discount(false), new Discount(true),
                     new Discount(false));
	}

}

Summary of actions:

1 – Created the Command interface.
2 – Created the request object (POJO).
3 – Created the Commands implementing the Command interface.
4 – Implemented the execute method in each Command.
5 – Created the CommandInvoker class to execute the commands.
6 – Invoked the Command through the InvokerCommand class.

To practice the Command Pattern you can create another Discount Command, for example, GoalDiscountCommand that is responsible for applying a Discount depending on the price the client paid for the product and create another test method to make sure it works! Try to use TDD (Test Driven Development). Start the development from the test. Remember, the only way to master the Design Patterns is by practicing them! So, I strongly recommend you clone the project and implement your new Discount Command!

DESIGN PATTERNS SAGA #7: REAL PROJECT SITUATIONS WITH COMMAND

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s