7 Mistakes Java Developers Make that Prevent to Refactor Bad Legacy Code

We all know that bad legacy code is a big problem. If we change any part of the code, everything can stop working. It’s a nightmare to maintain a software in this situation. Any simple bug turns into a big monster. Instead of trying to mend the code, refactor it!

But what are the mistakes we make to not refactor the code?

1 – Focus on Short Deadlines

In many companies, time is very short. We just spend a lot of time fixing the bugs, we test it, it works. Until then it’s ok, but most times another part of the application just breaks. Simply because the code is too coupled. If we fall in the illusion of correcting those bugs all the time because we don’t have time the consequence is that more bugs will appear.

2 – Focus on Numbers

Numbers, numbers, and numbers. We software developers have to take action to avoid situations where we have to generate numbers. If we accept generating numbers we will become part of the problem.

Sometimes we are told to fix 10 bugs but we again would be entering in the infinite cycle.

Fix bugs -> Generate other bugs -> Fix bugs -> Generate more bugs -> ….

The problem has to be solved by the root cause. The code must be refactored!

3 – Fear of Breaking the Application

It’s very common and natural to be afraid of breaking an important part of the application. Refactoring a bad legacy code without automated tests is obviously a risk.
What do you want to do? Do you want to be in your comfort-zone facing the nightmare of maintaining bad code? Sometimes we have to take the responsibility if something happens and be able to take action to reduce risks. A very simple action would be to get the test team by your side, you can create a separated branch to work and then, make it happen. Take action and improve the quality of the environment you are working for.

4 – Lack Negotiation Skills

Some time ago I thought that any other skill not being technical was useless. I was completely wrong. How can we propose a good technology for the project if we are unable to negotiate? Soft Skills are extremely important and we need to master them if we really want to do an amazing work. We can contribute much more improving them.

5 – Fear of Losing the Job

It’s tough to take the hard path, but certainly, it makes a great difference in your career. We want to cut the bad from the root. Also, you can lose your job breaking some important part of the software. That’s why you’ve got to bring everyone on your side to work with you, convince them to take the risk with you. It’s always better to see a high-quality code easy to maintain.

6 – Lack of business knowledge

We must be always curious about the business of the application we work on. How can we be sure everything is working fine if we don’t know the business? It’s not possible to test the application without knowing the business. Find a way to know better the business if you don’t know it yet. If you don’t have enough business knowledge you can always have someone by your side that can support you with this.

7 – Not knowing the  Best Programming Practices

To refactor the code in the best way we must know the best programming techniques. Simple things make a big difference like organized packages, method and variable names.

Simple concepts as well:

DRY – Don’t repeat yourself
KIS – Keep it simple
Apply Design Patterns

Remember, develop your code as if there is a psychopath that knows where you live maintaining your code.

What pill do you want to take? The blue one and keep everything in “control” inside your comfort zone? Or you want to take the red where you will face tough challenges but will make the world better?

There is more! You can get this FREE E-Book too!
No Bugs, No Stress – Create a Life-Changing Software Without Destroying Your Life

Keep up improving yourself!

7 Mistakes Java Developers Make that Prevent to Refactor Bad Legacy Code

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.

There is more! You can get this FREE E-Book too!
No Bugs, No Stress – Create a Life-Changing Software Without Destroying Your Life

Keep up improving yourself!

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!

There is more! You can get this FREE E-Book too!
No Bugs, No Stress – Create a Life-Changing Software Without Destroying Your Life

Keep up improving yourself!

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.

<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>public class InvalidProductException extends RuntimeException {

	private static final long serialVersionUID = -5415448783266469523L;

	@Override
	public String getMessage() {
		return "Invalid product.";
	}
}<span 				data-mce-type="bookmark" 				id="mce_SELREST_end" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

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 <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span><span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>< 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!

There is more! You can get this FREE E-Book too!
No Bugs, No Stress – Create a Life-Changing Software Without Destroying Your Life

Keep up improving yourself!

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!

There is more! You can get this FREE E-Book too!
No Bugs, No Stress – Create a Life-Changing Software Without Destroying Your Life

Keep up improving yourself!

 

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