Facade Design Pattern with Java

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 to 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).

Written by
Rafael del Nero
Join the discussion