Code Refactoring 13

Replace Conditional with CommandIn this part of my code refactoring tutorial, I’ll show you how to replace conditionals with the command pattern. I’m also going to do more though.

I’ll also review what the command pattern is. I’ll give an example of when you should use it. We’ll look at how to add flexibility with it. I’ll answer your questions based on the refactoring to patterns book. And, we’ll look at how to store commands in an ArrayList. If you need more look at my Command Design Pattern Tutorial and the code below.

If you like videos like this, it helps to tell Google+

Code from the Video

import java.util.ArrayList;

// Represents all the different types of BillPayers
// and the methods used by them
public interface BillPayer {
	
	public void calculateBill(double amountDue);

}

// Represents the methods that will change based off
// of different BillPayers
interface Command {
	
	public void executeCalculateBill(double amountDue);
	
}

// Different BillPayers
class WomanOver60 implements BillPayer{

	public void calculateBill(double amountDue) {
		
		System.out.println("Bill Amount for Woman Over 60: $" + (amountDue - (amountDue * .10)));
		
	}
	
}

class ManOver60 implements BillPayer{

	public void calculateBill(double amountDue) {
		
		System.out.println("Bill Amount for Man Over 60: $" + (amountDue - (amountDue * .05)));
		
	}
	
}

class ManUnder60 implements BillPayer{

	public void calculateBill(double amountDue) {
		
		System.out.println("Bill Amount for Man Under 60: $" + amountDue);
		
	}
	
}

// Command: Calls the right executeCalculateBill method
// based on the BillPayer type

class Waiter implements Command{
	
	BillPayer thePayer;
	
	Waiter(BillPayer thePayer){
		
		this.thePayer = thePayer;
		
	}

	public void executeCalculateBill(double amountDue) {
		
		thePayer.calculateBill(amountDue);
		
	}

}

// This is the invoker. When returnFinalBill() is called
// it executes the right executeCalculateBill() based
// on the object type stored in theCommand

// This invoker can except numerous Command types and
// then execute different methods based on the Command
// type, but here it is limited to just one

class CashRegister{
	
	Command theCommand;
	
	CashRegister(Command newCommand){
		
		theCommand = newCommand;
		
	}
	
	public void returnFinalBill(double amountDue){
		
		theCommand.executeCalculateBill(amountDue);
		
	}
	
}

// Returns the right BillPayer object based on the method called
// If I want to add another BillPayer I just update this and
// create a new BillPayer class (That's It)

class CustomerTypePicker{
	
	public static BillPayer getWomanOver60(){
		
		return new WomanOver60();
		
	}
	
	public static BillPayer getManOver60(){
		
		return new ManOver60();
		
	}
	
	public static BillPayer getManUnder60(){
		
		return new ManUnder60();
		
	}
	
}

// Group BillPayers into an ArrayList
// Now you can use these BillPayers as simple commands

class CustomerGroup{

	ArrayList<BillPayer> customers;
	
	CustomerGroup(){
		
		customers = new ArrayList<BillPayer>();
		
	}
	
	public void add(BillPayer newPayer){
		
		customers.add(newPayer);
		
	}
	
	public BillPayer get(int customerIndex){
		
		return customers.get(customerIndex);
		
	}

}

class UseCashRegister{
	
	public static void main(String[] args){
		
		// Get the customer to use for bill calculation
		
		BillPayer sallyMay = CustomerTypePicker.getWomanOver60();
		
		// The Waiter sets the customer type so that the right 
		// executeCalculateBill method is called
		
		Waiter theWaiter = new Waiter(sallyMay);
		
		// The invoker makes sure the right method is called and
		// stores the Waiter so BillPayers assigned to Waiter
		// are available
		
		CashRegister calculateBill = new CashRegister(theWaiter);
		
		// When returnFinalBill() is called that signals that the
		// Waiter stored in CashRegister should execute method
		// executeCalculateBill
		
		calculateBill.returnFinalBill(12.00);
		
		// Calculate for Man over 60
		
		BillPayer paulThumb = CustomerTypePicker.getManOver60();
		theWaiter = new Waiter(paulThumb);
		calculateBill = new CashRegister(theWaiter);
		calculateBill.returnFinalBill(12.00);
		
		// Call commands from the BillPayer ArrayList
		
		CustomerGroup custGroup = new CustomerGroup();
		custGroup.add(CustomerTypePicker.getWomanOver60());
		custGroup.get(0).calculateBill(12.00);
		
		
	}
	
}

// The Wrong Way
// 1. To add a new Customer type I have to change the Customer
// logic for returnFinalBill
// 2. Adding a new discount requires editing the class
// 3. If I want to implement a new calculation device I can't

class Customer{
	
	private int age;
	private boolean man;
	private double bill;
	
	public int getAge() { return age;}
	public void setAge(int age) { this.age = age;}
	public boolean isMan() {return man;}
	public void setMan(boolean man) {this.man = man;}
	
	public Customer(int age, boolean man, double bill) {
		this.age = age;
		this.man = man;
		this.bill = bill;
	}
	
	public void returnFinalBill(){
		
		double percentageOff = 0.0;
		
		if(age > 60){ percentageOff += .05; }
		if(!man){ percentageOff += .05; }
		
		System.out.println("Bill Amount: $" + (bill - (bill * percentageOff)));
		
	}
	
	public static void main(String[] args){
		
		Customer billSmith = new Customer(62, true, 12);
		
		billSmith.returnFinalBill();
		
	}
	
}

6 Responses to “Code Refactoring 13”

  1. Adi Ulici says:

    Hello Derek,

    Your code refactoring tutorials are amazing. They helped me a lot in understanding the design patterns, and I just wanted to say a big thanks (from me and, probably, almost all my colleagues at Computer Science from UBB University, Romania) – if it wasn’t for your videos I don’t know how I would’ve learned for my exam.

    Have a great day,
    Adi Ulici

    • Derek Banas says:

      Hello Adi,

      Thank you very much for the kind words 🙂 I’m very happy to have helped you and your colleagues. Your country is very beautiful and I’m honored that so many people from Romania seem to like my website.

      I’ll do my best to keep making good videos. Thank you for stopping to see my little website

      Derek

  2. Burale says:

    I have understood Command pattern in this video better than with your design pattern videos. You have also practically answered the question I asked at the end of Command Design Pattern video. Thanks man. You are helpful.

  3. Pawan Mittal says:

    All videos are amazing. When i saw first video, i could’t stop my self to watch further videos. Idea to explain the design patterns is really nice and quite interesting. Small video (duration 10-15 min) and simple coding examples makes all this interesting.

    But i am confused in Strategy and Command patterns by seeing the videos. Same kind of “discount calculation” concept is used for both patterns. So can you please make it more clear when to use which one.

    Thanks

    • Derek Banas says:

      Thank you very much 🙂 I’m happy that you enjoyed them.

      The Strategy Pattern is used to hide the implementation of the solution. Then many different ways to solve a problem can be used with the same interface.

      The Command Pattern specializes in creating a specific object that solves a very specific problem all on its own.

      I hope that helps

Leave a Reply

Your email address will not be published.

Google+