DESIGN PATTERNS SAGA #16: REAL PROJECT SITUATIONS WITH COMPOSITE

Composing objects without a pattern can make code really messy – code repetition happens a lot and maintenance is terrible. Fortunately, there is the Composite pattern that solves this problem completely. Using the Composite pattern we can encapsulate the code in just one place and compose the object more easily.

There are some frameworks that use the Composite pattern, such as JSF. It’s possible to reference all HTML components through the component’s classes from JSF.

This is a simple example of Web components being composed by the Composite pattern.

composite_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – UIComponent generic class: Every web component will inherit UIComponent, so we will be using polymorphism with this abstract class.

There are some necessary methods to enable the composition of objects.

add(UIComponent uiComponent): Adds any component.
remove(UIComponent uiComponent): Removes any component.
toString(): Prints the components code when they are composed.

public abstract class UIComponent {

	List<UIComponent> uiComponents = new ArrayList<>();

	public UIComponent add(UIComponent uiComponent) {
		throw new UnsupportedOperationException
			("Feature not implemented at this level");
	}

	public UIComponent remove(UIComponent uiComponent) {
		throw new UnsupportedOperationException
			("Feature not implemented at this level");
	}

	public abstract String toString();

}

2 – Components classes: These are the classes that will extend UIComponent. Basically, they are the actual components.

Form: It is a component that will be composed by others. As we developers know, the form tag is vastly used in every web application, so we are going to add components inside the Form component.
InputText: We are going add InputText instances in the Form component.
LabelText: We are going to add LabelText instances in the Form component.

public class Form extends UIComponent {

	String name;

	public Form(String name) {
		this.name = name;
	}

	@Override
	public UIComponent add(UIComponent uiComponent) {
		uiComponents.add(uiComponent);

		return uiComponent;
	}

	@Override
	public UIComponent remove(UIComponent uiComponent) {
		uiComponents.remove(uiComponent);

		return uiComponent;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder
               ("<form name='").append(name).append("'>");
		uiComponents.forEach(
                   e -> builder.append("\n").append(e));
		builder.append("\n</form>");
		return builder.toString();
	}
}

public class InputText extends UIComponent {

	String name;
	String value;

	public InputText(String name, String value) {
		this.name = name;
		this.value = value;
	}

	@Override
	public String toString() {
		return new StringBuilder("<inputText name='")                                                                        
                .append(name).append("' value='").append(value) 				                                                                        
                .append("'/>").toString();
	}
}

public class LabelText extends UIComponent {

	String value;

	public LabelText(String value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return new StringBuilder("<label value='")                                                                           .append(value).append("'/>").toString();
	}
}

3 – Unit Tests: Let’s use the Composite pattern now. We will instantiate and add the other components in the Form class. Then we will confirm if the Components code is correct with the assertion. There is another test with a composition of Maps showing this pattern with Java API.

public class CompositeTest {

	public static final int EXPECTED_MAP_SIZE = 3;

	@Test
	public void compositeTest() {
		Form mainForm = new Form("frmCustomer");

		LabelText lblCustomerName = new LabelText("Customer name:");
		InputText txtCustomerName = new InputText("txtCustomerName",
				"Juggy");

		LabelText lblCustomerProduct = new LabelText("Product:");
		InputText txtCustomerProduct = new
                InputText("txtCustomerProduct", <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>"Alienware laptop");

		mainForm.add(lblCustomerName);
		mainForm.add(txtCustomerName);
		mainForm.add(lblCustomerProduct);
		mainForm.add(txtCustomerProduct);

		Assert.assertEquals("<label value='Customer name:'/>",
				lblCustomerName.toString());
		Assert.assertEquals("<inputText name='txtCustomerName'" 				+ " value='Juggy'/>",
				txtCustomerName.toString());
		Assert.assertEquals("<inputText name='txtCustomerProduct'" 				+ " value='Alienware laptop'/>",
				txtCustomerProduct.toString());
		Assert.assertEquals("<label value='Product:'/>",
				lblCustomerProduct.toString());
	}

	@Test
	public void javaAPICompositeTest() {
		Map<String, String> topWebComponents = new HashMap<>();

		topWebComponents.put("Component1", "HTML");
		topWebComponents.put("Component2", "InputText");

		Map<String, String> normalWebComponents = new HashMap<>();

		normalWebComponents.put("Component3", "LabelText");

		Map<String, String> container = new HashMap<>();

		container.putAll(topWebComponents);
		container.putAll(normalWebComponents);

		Assert.assertEquals(EXPECTED_MAP_SIZE, container.size());
	}

}

Summary of actions:

  1. Created the UIComponent generic class.
  2. Created add, remove and toString method inside UIComponent.
  3. Created the objects that will be inside the UIComponent.
  4. Composed the objects and printed the code.

To practice the Composite pattern you can create another Component class and add inside the Form and then print out the code to make the test pass. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #16: REAL PROJECT SITUATIONS WITH COMPOSITE

DESIGN PATTERNS SAGA #15: REAL PROJECT SITUATIONS WITH STATE

When it’s necessary to maintain State from an object we can create a big code full of ifs controlling the State from the class. Certainly, this is not the right approach to solve this problem. Repetition of code is what we must avoid, we must follow the DRY (Don’t repeat yourself) principle to keep the code flexible and powerful.

state_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

Let’s first see a bad example of a “State” implementation.

1 – State Bad Example: There are two constants, OPEN and CLOSED. Whenever the openWindow or closeWindow methods are invoked all the rules will be manipulated inside them. As you can see in the code below, there is repetition.

public class AutomaticWindow {

	final static int CLOSED = 0;
	final static int OPEN = 1;

	int state = CLOSED;

	public AutomaticWindow() {
		super();
	}

	public void openWindow() {
		if (state == OPEN) {
			System.out.println("Window is already open");
		} else if (state == CLOSED) {
			System.out.println("Opening window.");
			state = OPEN;
		}
	}

	public void closeWindow() {
		if (state == OPEN) {
			System.out.println("Closing window.");
			state = CLOSED;
		} else if (state == CLOSED) {
			System.out.println("Window is already closed.");
		}
	}

	public String toString() {
		if (state == OPEN) {
			return "Window is open";
		} else {
			return "Window is closed";
		}
	}
}

Let’s now see how to use the State pattern for real! You will see the difference of a much cleaner and flexible code.

1 – State: It is the generic abstract class that handles the request from any class that must keep the State.

public abstract class State {

	public abstract void handleRequest();

}

2 – State concrete classes: They are basically the classes that extend the State class. They are responsible for changing the State to the next one in the sequence.

public class GreenTrafficLightState extends State {

	private TrafficLight trafficLight;

	public GreenTrafficLightState(TrafficLight trafficLight) {
		this.trafficLight = trafficLight;
	}

	@Override
	public void handleRequest() {
		System.out.println("Turning traffic light to yellow.");
		trafficLight.setState(trafficLight.getYellowLightState());
	}

	public String toString() {
		return "Traffic light is green.";
	}
}

public class RedTrafficLightState extends State {

	private TrafficLight trafficLight;

	public RedTrafficLightState(TrafficLight trafficLight) {
		this.trafficLight = trafficLight;
	}

	@Override
	public void handleRequest() {
		System.out.println("Turning traffic light to green...");
		trafficLight.setState(trafficLight.getGreenLightState());
	}

	public String toString() {
		return "Traffic light is on red.";
	}
}

public class YellowTrafficLightState extends State {

	private TrafficLight trafficLight;

	public YellowTrafficLightState(TrafficLight trafficLight) {
		this.trafficLight = trafficLight;
	}

	@Override
	public void handleRequest() {
		System.out.println("Turning traffic light to red.");
		trafficLight.setState(trafficLight.getRedLightState());
	}

	public String toString() {
		return "Traffic light is yellow.";
	}
}

3 – Orchestrator: This class is responsible for orchestrating the changes of the traffic lights’ State. In the constructor, we initialize all the States and we pass the same instance in the constructor to each one of the States classes. In the changeState method, we just delegate the call to the State instance variable to change the State.

public class TrafficLight {

	State red;
	State yellow;
	State green;

	State state;

	public TrafficLight() {
		red = new RedTrafficLightState(this);
		yellow = new YellowTrafficLightState(this);
		green = new GreenTrafficLightState(this);

		state = red;
	}

	public void changeState() {
		state.handleRequest();
	}

	public String toString() {
		return state.toString();
	}

	public State getGreenLightState() {
		return green;
	}

	public State getYellowLightState() {
		return yellow;
	}

	public State getRedLightState() {
		return red;
	}

	public void setState(State state) {
		this.state = state;
	}
}

4- Unit Tests: Now let’s see if the states are changing as expected. We are expecting that traffic lights change from red to green, yellow to red and so forth. In the window case, we want it to open and close.

public class StateTest {

	@Test
	public void stateTest() {
		TrafficLight trafficLight = new TrafficLight();

		trafficLight.changeState();

		trafficLight.changeState();

		trafficLight.changeState();

		trafficLight.changeState();

		Assert.assertEquals(trafficLight.state.getClass(),
				GreenTrafficLightState.class);
	}

	@Test
	public void badExampleStateTest() {
		AutomaticWindow automaticWindow = new AutomaticWindow();

		automaticWindow.openWindow();

		automaticWindow.closeWindow();

		Assert.assertEquals(automaticWindow.toString(),
				"Window is closed");
	}

}

Summary of actions:

  1. Created the State abstract generic class.
  2. Created the State classes that extend the State class.
  3. Implemented the handleRequest method from the State class.
  4. Created the TrafficLight class to manipulate the States.
  5. Created the changeState method in the TrafficLight class.

To practice the State Pattern you can create another State class with another scenario, for example changing any light state or anything else. Keep in mind that practicing the Patterns is crucial to fully master them.  Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #15: REAL PROJECT SITUATIONS WITH STATE

DESIGN PATTERNS SAGA #14: REAL PROJECT SITUATIONS WITH VISITOR

Sometimes we need to implement different methods for a POJO with different business requirements. We could certainly create several methods inside the POJO but we would not be utilizing the main benefits of powerful code – cohesion and low coupling. When we want to encapsulate different business requirements inside a cohesive class we can use the Visitor Pattern!

Basically, when using Visitor Pattern we encapsulate the business requirements inside the Visitor classes making our code very flexible.

visitor_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

Let’s see a bad example of code if we aren’t using the Visitor Pattern.

1 – Generic Interface: It’s basically the interface that declares the main method to calculate shipping.

public interface CardDevice {
	public double calculateShipping();
}

2 – Business POJOs: Now we have all the POJOs implementing the Generic interface in order to define the behavior to calculate shipping.

public class Mobile implements CardDevice {
	@Override
	public double calculateShipping() {
		return 6;
	}
}

public class WiredPos implements CardDevice {
	@Override
	public double calculateShipping() {
		return 9;
	}
}

public class WirelessPos implements CardDevice {
	@Override
	public double calculateShipping() {
		return 7;
	}
}

3 – Invoker: Now we can see the problem. We have the code very coupled with the specific calculateShipping method.

public class CardDeviceOrder implements CardDevice {

	private List<CardDevice> cardDevices = new ArrayList<>();

	public CardDeviceOrder() {
		super();
	}

	public void addPart(CardDevice cardDevice) {
		cardDevices.add(cardDevice);
	}

	public List<CardDevice> getCardDevices() {
		return Collections.unmodifiableList(cardDevices);
	}

	public double calculateShipping() {
		double shippingCost = 0;
		for (CardDevice cardDevice : cardDevices) {
			shippingCost += cardDevice.calculateShipping();
		}
		return shippingCost;
	}

}

4 – Unit Test: Let’s see if the calculateShipping method is working:

public class BadExampleVisitorTest {

	public static final double EXPECTED_SHIPPING_COST = 22.0;

	@Test
	public void visitorBadExampleTest() {
		CardDeviceOrder order = new CardDeviceOrder();
		order.addPart(new Mobile());
		order.addPart(new WiredPos());
		order.addPart(new WirelessPos());

		double shippingCost = order.calculateShipping();

		Assert.assertTrue(EXPECTED_SHIPPING_COST == shippingCost);
	}

}

Now let’s see the same example using the Visitor Pattern. Now you will realize that we will have more flexibility in the code.

1 – Visitor interface: We are going to define every business requirement inside this Visitor in order to manipulate these rules in an uncoupled mode. We are going to implement the rules inside the Visitor implementation.

public interface CardDeviceVisitor {
	void visit(WirelessPos wirelessPos);
	void visit(Mobile mobile);
	void visit(WiredPos wiredPos);
	void visit(CardDeviceOrder cardDeviceOrder);
}

2 – Visitor implementations: You will realize that the business requirements are implemented directly in the Visitor classes. They implement the Visitor generic interface and execute what is necessary for the business.

CardDeviceDisplayVisitor: Displays basic device information.
CardDeviceShippingVisitor: Calculates the shipping from each card device.

public class CardDeviceDisplayVisitor implements CardDeviceVisitor {

	@Override
	public void visit(WirelessPos wirelessPos) {
		System.out.println("We have a: " +  wirelessPos);
	}

	@Override
	public void visit(Mobile mobile) {
		System.out.println("We have a: " + mobile);
	}

	@Override
	public void visit(WiredPos wiredPos) {
		System.out.println("We have: " + wiredPos);
	}

	@Override
	public void visit(CardDeviceOrder cardDeviceOrder) {
		System.out.println("We have an: "+ cardDeviceOrder);
	}

}

public class CardDeviceShippingVisitor implements CardDeviceVisitor {

	double shippingValue = 0;

	@Override
	public void visit(WirelessPos wirelessPos) {
		System.out.println("Calculating Wireless Pos shipping.");
		shippingValue += 15;
	}

	@Override
	public void visit(Mobile mobile) {
		System.out.println("Calculating Mobile shipping");
		shippingValue += 3;
	}

	@Override
	public void visit(WiredPos wiredPos) {
		System.out.println("Calculating Wired Pos shipping.");
		shippingValue += 9;
	}

	@Override
	public void visit(CardDeviceOrder order) {
		System.out.println("If they bought more than 3 things "
				+ "there will be a discount in the shipping.");
		List<CardDevice> cardDevices = order.getCardDevices();
		if (cardDevices.size() > 3) {
			shippingValue -= 5;
		}
		System.out.println("Shipping amount is: " + shippingValue);
	}

	public double getShippingValue() {
		return shippingValue;
	}
}

3 – Business POJOs: We can clearly see that the POJOs are already different. They are not invoking the method to execute the specific business requirements. Now we invoke a method from a generic visitor. It decouples the code and the business requirement is manipulated inside the Visitor. Check it out:

public class Mobile implements CardDevice {
	@Override
	public void accept(CardDeviceVisitor visitor) {
		visitor.visit(this);
	}
}

public class WiredPos implements CardDevice {
	@Override
	public void accept(CardDeviceVisitor visitor) {
		visitor.visit(this);
	}
}

public class WirelessPos implements CardDevice {
	@Override
	public void accept(CardDeviceVisitor visitor) {
		visitor.visit(this);
	}
}

4 – Orchestrator, Invoker: The CardDeviceOrder class is responsible for orchestrating the cardDevices classes and invoking every method from the Visitors according to the specific Visitor class implementation.

public class CardDeviceOrder implements CardDevice {

	private List<CardDevice> cardDevices = new ArrayList<>();

	public CardDeviceOrder() {
		super();
	}

	public void addPart(CardDevice cardDevice) {
		cardDevices.add(cardDevice);
	}

	public List<CardDevice> getCardDevices() {
		return Collections.unmodifiableList(cardDevices);
	}

	@Override
	public void accept(CardDeviceVisitor visitor) {
		for (CardDevice cardDevice : cardDevices) {
			cardDevice.accept(visitor);
		}
		visitor.visit(this);
	}
}

5 – Unit Tests: Let’s test our Visitors! You will see the business methods being invoked through the Visitor classes.

First, add all the devices to the list of CardDeviceOrder.
Second, instantiate both visitors and pass them into the accept method from CardDeviceOrder.
Third, confirm the calculated shipping value is correct.

public class GoodExampleVisitorTest {

	public static final double EXPECTED_SHIPPING_COST = 27.0;

	@Test
	public void visitorGoodExampleTest() {
		CardDeviceOrder order = new CardDeviceOrder();
		order.addPart(new WirelessPos());
		order.addPart(new Mobile());
		order.addPart(new WiredPos());

		CardDeviceShippingVisitor shipping
			= new CardDeviceShippingVisitor();

		order.accept(shipping);
		order.accept(new CardDeviceDisplayVisitor());

		Assert.assertTrue(EXPECTED_SHIPPING_COST ==
				shipping.getShippingValue());
	}

}

Summary of actions:

  1. Created the Visitor generic interface.
  2. Implemented the Visitor classes with the necessary business requirements.
  3. Created the business POJOs delegating responsibilities to the Visitor classes.
  4. Created the orchestrator class responsible to manipulate the invocations.

To practice the Visitor Pattern you can create another Visitor class with another specific business requirement, for example calculating the rent from every card device. Create another test method to make sure it works. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #14: REAL PROJECT SITUATIONS WITH VISITOR

DESIGN PATTERNS SAGA #13: REAL PROJECT SITUATIONS WITH MEMENTO

What if we need to keep many different states of an object? We could keep the information inside objects with a lot of setters and make the code a big mess. This would indeed work but it would be awful to change anything in the future. As we developers know, software that does not change is dead.

When we need to manipulate different states of an object we can use the Memento Pattern.

memento_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Memento: Nothing special here, it is just the object information we encapsulated in order to keep only part of the Customer information.

 public class CustomerMemento {

	private String name;
	private String phone;

	public CustomerMemento(String name, String phone) {
		this.name = name;
		this.phone = phone;
	}

        // Getters and setters, hashcode and equals omitted.

}

2 – Caretaker: it encapsulates the Memento object history in a Stack.

Methods:
save: it saves the state of the CustomerMemento object, pushing it to the top of the Stack.

revert: it reverts the state of the CustomerMemento to the last saved state.

public class Caretaker {

	private Stack<CustomerMemento> customerHistory = new Stack<>();

	public void save(Customer customer) {
		customerHistory.push(customer.save());
	}

	public void revert(Customer customer) {
		customer.revert(customerHistory.pop());
	}

}

3 – Originator: This is the main Customer object, the Originator of the information. There are two important methods here:

save: sets the name and phone from the Customer in the CustomerMemento object and returns the CustomerMemento.

revert: it reverts the Customer with the CustomerMemento information.

 public class Customer implements Serializable {

	private static final long serialVersionUID = 574314732983681621L;
	private String name;
	private String address;
	private String phone;

	public Customer(String name, String address, String phone) {
		this.name = name;
		this.address = address;
		this.phone = phone;
	}

        public CustomerMemento save() {
		return new CustomerMemento(name, phone);
	}

	public void revert(CustomerMemento customer) {
		this.name = customer.getName();
		this.phone = customer.getPhone();
	}

        // Getters and setters, hashcode and equals omitted.
}

Summary of actions:

  1. Created the Memento class with the necessary information.
  2. Created the Caretaker class.
  3. Declared the Stack to keep the Memento information into the Caretaker.
  4. Created the Originator class with all the Customer’s information.
  5. Created the save method that returns the CustomerMemento object.
  6. Created the revert method to put CustomerMemento information into Customer.

To practice the Memento Pattern you can create other CaretakerOriginator and Memento classes and make it work. Create another test method to make sure it works. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #13: REAL PROJECT SITUATIONS WITH MEMENTO

DESIGN PATTERNS SAGA #12: REAL PROJECT SITUATIONS WITH MEDIATOR

What should be done when we need to use a functionality that may be repeated in several classes? Should we repeat the code in all the classes? If the behavior of this functionality changes, you will be obligated to change it in the entire project and test everything. This would not be cool. Fortunately, there is a solution for this problem – we can use the Mediator Pattern!

Using the Mediator Pattern can encapsulate this behavior inside just one class allowing us to reuse this method in every necessary class. Doing this will result in cohesive code with low coupling.

mediator_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Mediator: This class will be responsible to mediate the necessary behavior of calculating the Discount. This pattern is pretty straightforward, it simply mediates functionality.

public class DiscountCalculatorMediator {

	private BigDecimal productValue;

	private BigDecimal DISCOUNT_RATE = new BigDecimal("0.10");

	public DiscountCalculatorMediator(BigDecimal productValue) {
		this.productValue = productValue;
	}

	public BigDecimal calculate() {
		return productValue.
                  subtract(productValue.multiply(DISCOUNT_RATE));
	}

}

2 – Product POJO: We are going to mediate the calculateDiscount method to the Mediator class, and therefore we are not going to have the same code in different parts of the system. We will have this code only in the Mediator.

 public class Product {

	private BigDecimal productValue;

	public Product(BigDecimal productValue) {
		this.productValue = productValue;
	}

	public BigDecimal calculateDiscount() {
		return new DiscountCalculatorMediator
                  (productValue).calculate();
	}

}

Summary of actions:

  1. Created the Mediator class.
  2. Created the calculateDiscount behavior inside the Mediator.
  3. Reused the Mediator in the POJO.

To practice the Mediator Pattern you can create another Mediator class where you encapsulate a specific behavior and just reuse it in a method. Create another test method to make sure it works. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #12: REAL PROJECT SITUATIONS WITH MEDIATOR

DESIGN PATTERNS SAGA #11: REAL PROJECT SITUATIONS WITH ITERATOR

Most of the time we use the Iterator from the Collections API. It’s very important to know how to implement a customized Iterator in order to understand what is happening behind the scenes. If we read Java source code, for example, we are going to find out that the elements from ArrayList are actually manipulated in a normal array. If we read Java source code we can greatly improve our programming skills. I strongly recommend that you make this a habit.

Iterator diagram:

iterator_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Iterator: This is the main class where we are able to iterate the objects. The first detail to be aware of is that we are implementing the Iterable interface using String as a generic type.

We are declaring an array of products and the index.

In the constructor, we are initializing the array of products with the size of 10 and assigning zero to the index.

In the add method, we are adding a new element inside the array. We simply check if the index is the same size as the initial size of the array, in this case, 10. If so, we are going to make the array 5 times larger than before. Following this process, we copy the old array information to the largerArray. Finally, we add the product to the final array.

In the iterator method, we are using an anonymous inner class that implements Iterator. If we are using the Iterator interface we must implement all of its methods.

Again, we are declaring the index to control the iteration.

Let’s see what happens on the Iterator methods:

hasNext: verifies if there is another element to be iterated. If the index from the iterator is lower than the size of the array and the element is different from null it means we have the next element.

next: gets the next element from the products. It simply refers to the next element from the array and returns it.

remove: it copies the old array without the removed position, returning the removed element.

public class ProductRepository implements Iterable<String> {

	private String[] products;
	private int index;

	public ProductRepository() {
		products = new String[10];
		index = 0;
	}

	public void add(String product) {
		if (index == products.length) {
			String[] largerProducts = new String[
                            products.length + 5];
			System.arraycopy(products, 0, largerProducts,
                            0, products.length);
			products = largerProducts;
			largerProducts = null;
		}

		products[index++] = product;
	}

	@Override
	public Iterator<String> iterator() {
		return new Iterator<String>() {

			private int currentIndex = 0;

			@Override
			public boolean hasNext() {
				return currentIndex < products.length
                                  && products[currentIndex] != null;
			}

			@Override
			public String next() {
				return products[currentIndex++];
			}

			@Override
			public void remove() {
				System.arraycopy(products, currentIndex + 1,
                                  products, currentIndex, products.length - 1);
			}

		};
	}
}

2 – Unit Test: Now we are going to test the Iterator.

customIteratorTest: we add some elements, we get the iterator, remove two elements and check if the remaining element is “Tablet”.

javaAPIIteratorTest: we are just using the iterator from the Java Collections API, removing all the elements and checking if the Set Collection is empty.

 public class IteratorTest {

	@Test
	public void customIteratorTest() {
		ProductRepository repo = new ProductRepository();

		repo.add("Guitar");
		repo.add("Notebook");
		repo.add("Tablet");

		Iterator<String> productIterator = repo.iterator();
		productIterator.remove();
		productIterator.remove();

		Assert.assertEquals(productIterator.next(), "Tablet");
	}

	@Test
	public void javaAPIIteratorTest() {
		Set<String> simpsons = new HashSet<>();

		simpsons.add("Homer");
		simpsons.add("Bart");
		simpsons.add("Margie");

		Iterator<String> simpsonsItr = simpsons.iterator();

		while (simpsonsItr.hasNext()) {
			String name = simpsonsItr.next();
			System.out.println(name);
			simpsonsItr.remove();
		}

		Assert.assertEquals(0, simpsons.size());
	}

}

Summary of actions:

  1. Created the Iterator class.
  2. Encapsulated an array inside the Iterator class.
  3. Implemented the Iterable interface in the Iterator class.
  4. Overrode the iterator method.
  5. Created an anonymous inner class of the Iterator type.
  6. Overrode all the methods from the Iterator interface.

To practice the Iterator Pattern you can create another Repository and iterate over the elements from it. Create another test method to make sure it works. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #11: REAL PROJECT SITUATIONS WITH ITERATOR

DESIGN PATTERNS SAGA #10: REAL PROJECT SITUATIONS WITH FACADE

Sometimes we have to deal with complex methods where there are many processes and it’s necessary to orchestrate them every time and repeat the code many times.

There are other situations in which the methods are very confusing and difficult to understand. How can a new developer discover what method to invoke if everything is confusing? He would probably ask a more experienced developer to explain what is happening. Even developers that already know the project might be confused and would spend a good amount of time trying to understand what is happening.

Fortunately, there is a solution for this problem! We can use the Facade Pattern and make it easy to understand! Several actions can be encapsulated and orchestrated inside a Facade!

Important points about the Facade Pattern:

  • Simplifies readability.
  • Avoids code repetition.
  • Simplifies legacy code processes to use.
  • Encapsulates actions in one simplified method.

facade_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Classes to be orchestrated: The main reason to use the Facade Pattern is to orchestrate some confusing/complex tasks so they become easier to understand. In this example, we want to execute the logic to apply a discount. It’s not so simple because there are many processes to accomplish it. Now we are going to see all the necessary classes to execute all the logic.

public class CustomerService {

	private Map<Long, Customer> customers = new HashMap<>();

	public CustomerService() {
		customers.put(1L, new Customer("Vader", "Imperial City",
                  new Date()));
	}

	public Customer findProductBy(long idCustomer) {
		return customers.get(idCustomer);
	}

}

public class ProductService {

	private Map<Long, Product> products = new HashMap<>();

	public ProductService() {
		products.put(1L, new Product(1L, "POS", new BigDecimal("100")));
	}

	public Product findProductBy(long idProduct) {
		return products.get(idProduct);
	}

}

public class DiscountService {

	public void applyDiscount(Customer customer, Product product) {
		System.out.println("Applying discount for customer: "
                                 + customer.getName() +
				  " product: " + product.getName());
	}

}

public class Product {
	private long idProduct;
	private String name;
	private BigDecimal price;

	public Product(long idProduct, String name, BigDecimal price) {
		this.idProduct = idProduct;
		this.name = name;
		this.price = price;
	}

        // Getters and setters omitted

}

public class Customer {

	private String name;
	private String address;
	private Date birthDate;

	public Customer(String name, String address, Date birthDate) {
		this.name = name;
		this.address = address;
		this.birthDate = birthDate;
	}

       // Getters and setters omitted
}

public class ApplyDiscountRequest {

	private long idCustomer;
	private long idProduct;
	private long idDiscount;

	public ApplyDiscountRequest(long idCustomer, long idProduct,
                long idDiscount) {
		this.idCustomer = idCustomer;
		this.idProduct = idProduct;
		this.idDiscount = idDiscount;
	}

       // Getters and setters omitted
}

2 – Facade: Now let’s organize the code! In order to apply a discount, there are many actions to be executed, that’s why we are going to use the Facade Pattern to orchestrate all these processes.


public class DiscountFacade {

	private CustomerService customerService = new CustomerService();
	private ProductService productService = new ProductService();
	private DiscountService discountService = new DiscountService();

	public boolean applyDiscount(ApplyDiscountRequest discountRequest) {
		Customer customer = customerService
                   .findProductBy(discountRequest.getIdCustomer());

		Product product = productService
                   .findProductBy(discountRequest.getIdProduct());

		discountService.applyDiscount(customer, product);
		boolean isDiscountApplied = true;

		return isDiscountApplied;
	}

}

3 – Unit Test: Let’s test if our Facade is working! It’s very simple now, we just have to invoke the Facade!

public class FacadeTest {

	private DiscountFacade facade;

	@Before
	public void init() {
		facade = new DiscountFacade();
	}

	@Test
	public void applyDiscountTest() {
		boolean isDiscountApplied = facade.applyDiscount(
                 new ApplyDiscountRequest(1L, 1L, 1L));

		Assert.assertTrue(isDiscountApplied);
	}

}

Summary of actions:

  1. Created the classes to be orchestrated.
  2. Created the Facade class.
  3. Orchestrated all the necessary logic in the Facade.
  4. Encapsulated all the actions to apply a discount to a customer.

To practice the Facade Pattern you can create other actions to be orchestrated and simplified. For example, changing the customer’s plan or anything you want to practice the Pattern. Create another test method to make sure it works. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #10: REAL PROJECT SITUATIONS WITH FACADE