7 Steps to Convince Java Developers to Implement Better Code

When software developers don’t care about producing a good code all the environment tends to be impacted by the consequences. Bad code leads to a stressful environment full of bugs where you don’t have time for you and your family. That’s why we will explore the 7 steps to avoid this problem.

1 – Be a Reference

If you need your team to produce a high-quality code, you must be a reference. It doesn’t matter if you are not the team leader; we can take the lead of anything without a title for the greater benefit. Share your knowledge with the team you work with, show them new programming techniques. Motivate them to be thirsty for more knowledge so that they can study by themselves. If your team admires your work, certainly they will be more willing to be like you.

2 – Show them the wasted time to fix a simple bug

How much time have we spent trying to find/fix a bug when the code was really bad? Much time indeed, it may have lasted for one or two days or maybe one week? Yes, this is the impact of producing a bad code. How many times did we have to find out what was the meaning of a variable or method because of poor names that don’t mean anything? We have to be detectives sometimes to find out what is happening.

Show them a giant do it all method and make them realize how stressful is to fix a bug under those conditions. That’s why we have to know how to convince and influence the team to use the best programming practices. We must show them the price we pay when a bad code is produced.

3 – Don’t be arrogant

Many developers fall into this mistake of being arrogant. It’s very unlikely you will be able to influence people by being arrogant. People tend to be defensive when they are treated in a bad way and they won’t trust you or follow your leads. So, it’s simple, you must be the opposite, have the attitude of supporting your team without being too harsh. Show them the right path to follow.

4 – Show them how rewarding it is to write high-quality code

What if we had written bad code? Certainly, we would waste much time until we could understand what is happening.  It’s very rewarding when we see the code after some time and we are able to understand everything. If we put more effort when writing a code,  everyone wins. As we know, we spend 10 times as much time reading bad code than writing a high-quality code one.

5 – Use a quality-code tool

Tools like PMD/Checkstyle and Sonar don’t solve the problem entirely but certainly help. They prevent very ugly things in the code such as very long methods, huge classes, unused variables, and nested loopings. Just remember that you must configure these tools in the right way, or else you will be correcting everything in the code and it will be really annoying.

6 – Implement Code Review Culture

This is crucial to improve the code-quality from your team. Every time someone finishes their tasks the Code Review must be executed. You must make other members of your team learn the best programming practices so they can work on their own.

7 – Implement Knowledge Transfer Culture

Certainly, the culture of sharing knowledge in your team is extremely powerful. You will be improving your speaking skills and will be learning new content that is crucial for your daily work. You can prepare Knowledge Transfer about best programming practices techniques, frameworks, tests, whatever you find your team needs most.

7 Steps to Convince Java Developers to Implement Better Code

DESIGN PATTERNS SAGA #20: REAL WORLD SITUATIONS WITH OBSERVER

Do you remember how to use the Swing API with action events? If not, refresh your memory here:

    // main method......
    someComponent.addActionListener(new ActionExample());

public class ActionExample implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        ...//code that reacts to the action...
    }
}

When using the Swing API you also use the Observer pattern maybe even without realizing it. The Observer pattern enables us to decouple the observed actions and isolate each process that must be executed. It’s clear that we will gain flexibility and cohesion.

observer_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Observer: It’s the generic abstract class that enables us to implement the Observer pattern. We will use the most powerful feature of Object Oriented programming, the Polymorphism. It’s crucial to fully master Polymorphism when using the Design Patterns.

public abstract class Observer {
	protected Subject subject;
	abstract void update();
}

2 – Subject: It orchestrates the necessary actions that must be executed when using the Observers. The Subject class contains the generic methods to be reused at the specific Subject class.

public abstract class Subject {

	private List<Observer> observers = new ArrayList<>();

	abstract void setState(String state);
	abstract String getState();

	public void attach(Observer observer) {
		observers.add(observer);
	}

	public void notifyObservers() {
		for (Observer observer : observers) {
			observer.update();
		}
	}
}

3 – Subject specialization: In this class, we are defining the specific actions to be executed by any Observer class.

public class MessageStream extends Subject {

	private Deque<String> messageHistory = new ArrayDeque<>();

	@Override
	void setState(String message) {
		messageHistory.add(message);
		this.notifyObservers();
	}

	@Override
	String getState() {
		return messageHistory.getLast();
	}
}

4 – Observers specializations: Finally the Observers’ implementations! Basically, to make everything work we add the subject in the Observers‘ constructors and invoke the addMessage method.

public class SlackClient extends Observer {

	public SlackClient(Subject subject) {
		this.subject = subject;
		subject.attach(this);
	}

	public void addMessage(String message) {
		subject.setState(message + " - sent from Slack");
	}

	@Override
	void update() {
		System.out.println("Slack Stream: " + subject.getState());
	}

} 

public class WhatsAppClient extends Observer {

	public WhatsAppClient(Subject subject) {
		this.subject = subject;
		subject.attach(this);
	}

	public void addMessage(String message) {
		subject.setState(message + " - sent from WhatsApp");
	}

	@Override
	void update() {
		System.out.println("WhatsApp Stream: " + subject.getState());
	}
}

5 – Unit Tests: Let’s see how it works. The use of the Observer pattern is pretty easy. Basically, we will instantiate the Subject specialization and pass it into the Observer specialization constructor. Then we will invoke the addMessage method and it’s done!

public class ObserverTest {

    @Test
    public void observerTest() {
        Subject subject = new MessageStream();

        WhatsAppClient whatsAppClient = new WhatsAppClient(subject);
        SlackClient slackClient = new SlackClient(subject);

        slackClient.addMessage("Another new message!");
        Assert.assertEquals("Another new message! " +
           "- sent from Slack", subject.getState());

        whatsAppClient.addMessage("Here is a new message!");
        Assert.assertEquals("Here is a new message! " +
           "- sent from WhatsApp", subject.getState());
    }

}

Summary of actions:

  1. Created the Observer abstract class
  2. Declared the Subject as a field inside the Observer abstract class
  3. Created the Subject abstract class
  4. Created the Subject specialization class
  5. Created the Observer specialization class
  6. Instantiated the Subject specialization class
  7. Created Observer specialization instances
  8. Passed the Subject instance to the Observer constructor
  9. Invoked the addMessage method from the Observers’ specialization

To practice the Observer pattern you can create another Subject or Observer. You could create a FileStreamSubject and InstagramClient, for example. It’s crucial to practice. Create at least one example and practice your programming skills using TDD!

DESIGN PATTERNS SAGA #20: REAL WORLD SITUATIONS WITH OBSERVER

DESIGN PATTERNS SAGA #19: REAL WORLD SITUATIONS WITH PROXY

To make code flexible and easy to maintain we must find a way to encapsulate and not repeat the code. What if we need to do a specific treatment every time we get an Exception? Would we repeat this code in the entire application? We could, but imagine how bad the maintenance would be. It would be much easier to use the power of the Proxy pattern. We can use Reflections in just one place and make our code extremely flexible.

A very simple example of Proxy is, for example, when the company you work for wants to block certain websites. They use Proxy to intercept non-work related sites.

proxy_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Interface: Nothing special here, it’s just the interface to invoke the Service.

public interface ContractProductService {
	public String contractProduct(Long idProduct);
}

2 – Specific Exception: Exception to be treated in the Proxy class.

public class InvalidProductException extends RuntimeException {

	private static final long serialVersionUID = -5415448783266469523L;

	@Override
	public String getMessage() {
		return "Invalid product.";
	}
}

3 – Service implementation: It’s a simulation of a product contract and a very simple verification to see how we can use the Proxy pattern.

public class ContractProductServiceImpl implements ContractProductService {

	public String contractProduct(Long idProduct) {
		if (idProduct &lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&gt;&lt;/span&gt;&lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&gt;&lt;/span&gt;&lt; 0) {
			throw new InvalidProductException();
		}

		return "Product contracted!";
	}

}

4 – Proxy: This is the main class where we intercept the method calls. The first important thing we are doing is the InvocationHandler interface implementation.

There are two crucial methods we use to intercept the methods invocations.

Object newInstance(Object obj): We are using the Proxy class from the Reflection API. When we instantiate any class by this method, it enables us to always intercept the method invocation.

Object invoke(Object proxy, Method m, Object[] args): It’s the method that will intercept the methods invocations when we use the method above. We are manipulating the actions if we get any Exception by any method invocation. We are simply using a JOptionPane to show the message that is thrown by any method invocation.

public class SecurityProxy implements InvocationHandler {

	private Object obj;

	private SecurityProxy(Object obj) {
		this.obj = obj;
	}

	public static Object newInstance(Object obj) {
		return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
                   .getClassLoader(), obj.getClass().getInterfaces(),
				new SecurityProxy(obj));
	}

	@Override
	public Object invoke(Object proxy, Method m, Object[] args)
             throws Throwable {
		Object result;
		try {
			result = m.invoke(obj, args);
		} catch (InvocationTargetException e) {
			JOptionPane.showMessageDialog(null,
                             e.getTargetException()
			     .getMessage());

			throw e.getTargetException();
		} catch (Exception exception) {
			throw new RuntimeException(exception);
		}
		return result;
	}

}

5 – Unit Tests: Let’s check out the use of the Proxy pattern now.

void proxyInvalidProductTest(): In this test we go through the InvalidProductException path. The first thing to understand is that we are creating the instance from the object by the newInstance method from the SecurityProxy class.

This is crucial because we need to get the instance from the SecurityProxy class to make the Proxy invocation work. Once we get the instance from the newInstance method then every method invocation will be intercepted.

void proxyValidProductTest(): It’s pretty similar to the method above. The method will also be intercepted but the difference is that we are passing a valid id to contract the product.

public class ProxyTest {

	public static final long INVALID_PRODUCT_ID = -1;
	public static final long VALID_PRODUCT_ID = 1;

	@Test(expected=InvalidProductException.class)
	public void proxyInvalidProductTest() {
		ContractProductService service =
                    (ContractProductService)SecurityProxy
		     .newInstance(new ContractProductServiceImpl());

		service.contractProduct(INVALID_PRODUCT_ID);
	}

	@Test
	public void proxyValidProductTest() {
		ContractProductService service =
                      (ContractProductService)SecurityProxy
		       .newInstance(new ContractProductServiceImpl());

		String result = service.contractProduct(VALID_PRODUCT_ID);

		Assert.assertEquals("Product contracted!", result);
	}
}

Summary of actions:

  1. Created a simple Service to intercept the method.
  2. Created the Proxy class.
  3. Created the newInstance method in the Proxy class.
  4. Created the invoke method that does the action in the intercepted methods.
  5. Created the instance from the Service thought the newInstance method.
  6. Intercepted and implemented the actions in the invoke method from the Proxy.

To practice the Proxy pattern you can create another rule in the invoke method or you can create another Service implementation. It’s crucial to practice. Use TDD for this example!

DESIGN PATTERNS SAGA #19: REAL WORLD SITUATIONS WITH PROXY

DESIGN PATTERNS SAGA #18: REAL WORLD SITUATIONS WITH FLYWEIGHT

There are some situations in software development in which we need to improve performance. This is possible with the use of Cache. Imagine a lot of the same objects being created and wasting memory. The Flyweight pattern was created to avoid this problem and optimize performance.

Flyweight_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – POJO: This is the object we will keep in the Cache.

class Product {
	private final String name;

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

	public String toString() {
		return name;
	}
}

2 – Factory (Cache): Basically this class is responsible to create the caches.

lookup(String productName): It checks if the product is contained in the map. If it is, we will return the product. If not, we will put the product on the map and return the product.

public class Portfolio {
	private Map<String, Product> products = new HashMap<String, Product>();

	/**
	 * Factory method Pattern
	 */
	public Product lookup(String productName) {
		if (!products.containsKey(productName))
			products.put(productName, new Product(productName));
		return products.get(productName);
	}

	public int totalProductsMade() {
		return products.size();
	}
}

3 – Object composer: It just composes the information from the product to execute the order.

public class Order {
	private final int orderNumber;
	private final Product product;

	Order(int orderNumber, Product product) {
		this.orderNumber = orderNumber;
		this.product = product;
	}

	void processOrder() {
		System.out.println("Ordering " + product +
				" for order number " + orderNumber);
	}
}

4 – Executor: Here is where the action happens.

void executeOrder(String productName, int orderNumber): It orchestrates the input in the map. If the product is in the map already, it will return the same object. If not, it will put the new information in the map and return it.

void process(): It will process all the orders and remove every product.

int getTotalProducts(): It will get the total of the registered products.

public class InventorySystem {

	private final Portfolio portfolio = new Portfolio();
	private final List<Order> orders = new CopyOnWriteArrayList<Order>();

	void executeOrder(String productName, int orderNumber) {
		Product product = portfolio.lookup(productName);
		Order order = new Order(orderNumber, product);
		orders.add(order);
	}

	void process() {
		for (Order order : orders) {
			order.processOrder();
			orders.remove(order);
		}
	}

	int getTotalProducts() {
		return portfolio.totalProductsMade();
	}
}

5 – Unit Tests: Let’s see if the cache is working!

public void flyweightTest(): At first we will invoke the executeOrder method from the InventorySystem and process it. When the products are added it automatically removes the duplication. In the end, we check if there are 3 products and the test passes.

public void flyweightJavaApiExampleTest(): There is something curious about Wrappers of Numbers in Java. When we use an Integer between -127 and 128 there is a Cache that maintains those numbers in order to avoid wasted memory.

public class FlyweightTest {

	@Test
	public void flyweightTest() {
		InventorySystem inventory = new InventorySystem();

		inventory.executeOrder("AlienWare laptop", 2500);
		inventory.executeOrder("SkullCandy HeadPhones", 150);
		inventory.executeOrder("Playstation 5", 500);
		inventory.executeOrder("SkullCandy HeadPhones", 130);
		inventory.executeOrder("AlienWare laptop", 3000);
		inventory.executeOrder("Playstation 5", 600);

		inventory.process();

		Assert.assertEquals(3, inventory.getTotalProducts());
	}

	@Test
	public void flyweightJavaApiExampleTest() {
		Integer firstInt = Integer.valueOf(5);

		Integer secondInt = Integer.valueOf(5);

		Integer thirdInt = Integer.valueOf(10);

		Assert.assertTrue(firstInt == secondInt);
		Assert.assertFalse(secondInt == thirdInt);
	}

}

Summary of actions:

  1. Created the POJO to keep in the Cache.
  2. Created the auxiliary classes to make the Flyweight pattern work.
  3. Created the map from the POJO to get rid of duplication.
  4. Map created from the POJO without duplications.

To practice the Flyweight pattern you can create another POJO and your own implementation to avoid duplication. Practice TDD with this example!

 

DESIGN PATTERNS SAGA #18: REAL WORLD SITUATIONS WITH FLYWEIGHT

DESIGN PATTERNS SAGA #17: REAL WORLD SITUATIONS WITH DECORATOR

There are some situations in which we need high flexibility. Let’s consider that we want to create a flexible code for mixing a lot of different pizzas. We would not want to write all the possibilities without a pattern, right? For this reason, we want to use the Decorator pattern to gain flexibility, high cohesion, and low coupling.

pizza_decorator.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Generic interface (Component): It’s the interface with the method that will create all of the objects’ decorations.

public interface Pizza {
	public String make();
}

2 – Decorator: This is the class that makes things happen. It is on the top of all decorator classes and is responsible for decorating the objects.

public abstract class PizzaDecorator implements Pizza {

	protected Pizza customPizza;

	public PizzaDecorator(Pizza customPizza) {
		this.customPizza = customPizza;
	}

	public String make() {
		return customPizza.make();
	}

}

3 – Decorator classes: These are the classes that will decorate the final pizza. Basically, we will decorate the pizza with the toppings we want in a flexible way.

public class TuscanyDecorator extends PizzaDecorator {

	public DressingDecorator(Pizza customPizza) {
		super(customPizza);
	}

	public String make() {
		return customPizza.make() + addTuscany();
	}

	private String addTuscany() {
		return " + Tuscany";
	}

}

public class MozzarellaDecorator extends PizzaDecorator {

	public MozzarellaDecorator(Pizza customPizza) {
		super(customPizza);
	}

	public String make() {
		return customPizza.make() + addMozzarella();
	}

	private String addMozzarella() {
		return " + Mozzarella";
	}
}

4 – Concrete component: This is the base of the pizza (the dough), the component that will generate different kinds of pizzas.

public class SimplePizza implements Pizza {

	@Override
	public String make() {
		return "Base";
	}
}

5 – Unit Tests: It’s test time! Now we will top the pizza in the way we want. We will instantiate the toppings first and then we use the base of the pizza – always passing the object in the constructor of each decorator class. In the end, we invoke the generic make method and the pizza is done!

Also, there is the Java API example with File creation.

public class DecoratorTest {

	@Test
	public void decoratorTest() {
		Pizza pizza = new TuscanyDecorator(
				new MozzarellaDecorator(new SimplePizza()));

		Assert.assertEquals("Base + Mozzarella + Tuscany"
                    , pizza.make());
	}

	@Test
	public void decoratorJavaAPITest() throws IOException {
		File file = new File("./output.txt");
		file.createNewFile();

		OutputStream stream = new FileOutputStream(file);

		DataOutputStream dataStream = new DataOutputStream(stream);
		dataStream.writeChars("text");
		dataStream.close();
		stream.close();

		file.delete();
	}

}

Summary of actions:

  1. Created the generic interface of the Component with the make method.
  2. Created the Component class implementing the generic interface.
  3. Created the Decorator abstract class controlling the decoration.
  4. Created the Decorator concrete classes extending the Decorator.
  5. Decorated the Component joining the classes in the constructor.

To practice the Decorator pattern you can create another Component class, for example, a Sandwich and decorate your Sandwich as you wish. Be sure to use TDD (Test Driven Development).

DESIGN PATTERNS SAGA #17: REAL WORLD SITUATIONS WITH DECORATOR

DESIGN PATTERNS SAGA #16: REAL WORLD 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", "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 WORLD SITUATIONS WITH COMPOSITE

DESIGN PATTERNS SAGA #15: REAL WORLD 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 WORLD SITUATIONS WITH STATE