# [Java] – Design Pattern : How to use ? With code examples and project for you understand

What is it ?

Design pattern is an elegant solution to a problem that recurs.

## STRATEGY

When ?

The Strategy pattern is very useful when we have a similar set of algorithms, and we need to switch between them in different pieces of the application.

Diagram :

Example

Problem : Calculate different types of taxes.

Solution :

```public class Invoice {
private double value;

public Invoice(double value) {
this.value = value;
}

public double getValue() {
return value;
}

private void setValue(double value) {
this.value = value;
}

}```
```public interface Tax {
double calculate(Invoice invoice);
}```
```public class FederalTax implements Tax {
@Override
public double calculate(Invoice invoice) {
return invoice.getValue() * 0.06;
}
}```
```public class CityTax implements Tax {
@Override
public double calculate(Invoice invoice) {
return invoice.getValue() * 0.1;
}

}```
```// CODE TEST
public class StrategyTest {
@Test
public void calulateTaxTest() {
Double price = 100.0;
CityTax cityTax = new CityTax();
FederalTax federalTax = new FederalTax();
Invoice invoice = new Invoice(price);
Double total = cityTax.calculate(invoice)
+ federalTax.calculate(invoice);
Double result = 16.0;
TestCase.assertEquals(total, result);
}
}```

## CHAIN OF RESPONSIBILITY

When ?

When we have a defined chain of behaviors that can be applied according to specific scenarios.

Diagram :

Example :

Problem : Apply distinct discounts in a order . Rules :

Apply discount if :

• order value > 500 = 10%
• order quantity itens > 5 = 20 % ( but the order value need be more than 500 )

Solution :

```public class Item {

private String name;
private double value;

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getValue() {
return value;
}

public void setValue(double value) {
this.value = value;
}
}```
```public class Order {
private List<Item> itens = new ArrayList<>();

public Order() {}

public double getValue() {
return this.getItens().stream()
.mapToDouble(i -> i.getValue())
.sum();
}

public List<Item> getItens() {
return Collections.unmodifiableList(itens);
}

}
}```
```public interface Discount {

double applyDiscount(Order order);
void callNext(Discount next);

}```
```public class DiscountFiveItens implements Discount {
private Discount next;

@Override
public double applyDiscount(Order order) {
if(order.getItens().size() > 5 && order.getValue() > 500) {
return order.getValue() * 0.2;
}
else {
return next.applyDiscount(order);
}
}

@Override
public void callNext(Discount next) {
this.next = next;
}
}```
```public class DiscountOrderBiggerThan500 implements Discount {
private Discount next;

@Override
public double applyDiscount(Order order) {
if(order.getValue() > 500) {
return order.getValue() * 0.1;
}
else {
return next.applyDiscount(order);
}
}

@Override
public void callNext(Discount next) {
this.next = next;
}
}```
```public class WhitoutDiscount implements Discount {
@Override
public double applyDiscount(Order order) {
return 0;
}

@Override
public void callNext(Discount next) {
// Don' have the next one.
}
}```
```public class DiscountCalculator {

public double calculate(Order order) {
Discount d1 = new DiscountFiveItens();
Discount d2 = new DiscountOrderBiggerThan500();
Discount d3 = new WhitoutDiscount();

d1.callNext(d2);
d2.callNext(d3);

return d1.applyDiscount(order);
}

}```
```// CODE TEST
public class ChainOfResponsabilityTest {

@Test
public void testWithoutDiscount(){
DiscountCalculator calculator = new DiscountCalculator();

Order order = new Order();

double discount = calculator.calculate(order);
double expectedResult = 0.0;

TestCase.assertEquals(discount, expectedResult);
}

@Test
public void testDiscountFiveItensLessThan500(){
DiscountCalculator calculator = new DiscountCalculator();

Order order = new Order();

double discount = calculator.calculate(order);
TestCase.assertTrue(discount == 0.0);
}

@Test
public void testDiscountFiveItensMoreThan500(){
DiscountCalculator calculator = new DiscountCalculator();

Order order = new Order();

double discount = calculator.calculate(order);
TestCase.assertTrue(discount == 200);
}

@Test
public void testDiscountOtherBiggerThan500(){
DiscountCalculator calculator = new DiscountCalculator();

Order order = new Order();

double discount = calculator.calculate(order);
TestCase.assertTrue(discount == 100);
}
}```

## TEMPLATE METHOD

When ?

Basically, it will be useful when you have the same implementation for more than one strategy.

Diagram :

Example :

Problem : Calculate different types of taxes, use the same scenario of the Strategy example. Also, the taxes need following this conditions:

• CityTax :

if invoice value is more than 500 and has a item with value more than 100 the tax is 10%, otherwise is 6%.

• FederalTax :

if invoice value is more than 500 the tax is 7%, otherwise is 5%.

Solution : Look we can say which both conditions are following this rule: if the scenario attend the first condition we should apply the maximum rate, otherwise we should apply the minimum rate.

```// CODE TEST
public class TemplateMethodTest {

@Test
public void calulateCityTaxMaximumRateTest() {
Invoice invoice = new Invoice();
Double result = new CityTax().calculate(invoice);
Double resultCityTexExp = invoice.getValue() * 0.1;
TestCase.assertEquals(result, resultCityTexExp);
}

@Test
public void calulateCityTaxMinimumRateTest() {
Invoice invoice = new Invoice();
Double result = new CityTax().calculate(invoice);
Double resultCityTexExp = invoice.getValue() * 0.6;
TestCase.assertEquals(result, resultCityTexExp);
}

@Test
public void calulateFederalTaxMaximumRateTest() {
Invoice invoice = new Invoice();
Double result = new FederalTax().calculate(invoice);
Double resultCityTexExp = invoice.getValue() * 0.7;
TestCase.assertEquals(result, resultCityTexExp);
}

@Test
public void calulateFederalTaxMinimumRateTest() {
Invoice invoice = new Invoice();
Double result = new FederalTax().calculate(invoice);
Double resultCityTexExp = invoice.getValue() * 0.5;
TestCase.assertEquals(result, resultCityTexExp);
}

}```
```public class CityTax extends TemplateConditionalInvoice {

@Override
public boolean isToApplyMaximunRate(Invoice invoice) {
return invoice.getValue() > 500 && hasItemValueMoreThan100(invoice);

}

private boolean hasItemValueMoreThan100(Invoice invoice) {
Optional<Item> invoiceOptional = invoice.getItens().stream()
.filter(i -> i.getValue() > 100)
.findFirst();
return invoiceOptional.isPresent();
}

@Override
protected double applyMaximumRate(Invoice invoice) {
return invoice.getValue() * 0.10;
}

@Override
protected double applyMinimumRate(Invoice invoice) {
return invoice.getValue() * 0.60;
}

}```
```public class FederalTax extends TemplateConditionalInvoice {

@Override
public boolean isToApplyMaximunRate(Invoice invoice) {
return invoice.getValue() > 500;
}

@Override
protected double applyMaximumRate(Invoice invoice) {
return invoice.getValue() * 0.70;
}

@Override
protected double applyMinimumRate(Invoice invoice) {
return invoice.getValue() * 0.50;
}
}```
```public class Invoice {

private List<Item> itens = new ArrayList<>();
public Invoice() {}

public List<Item> getItens() {
return Collections.unmodifiableList(itens);
}

}

public double getValue() {
return this.getItens().stream().mapToDouble(i -> i.getValue()).sum();
}

}```
```public class Item {

private String name;
private double value;

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getValue() {
return value;
}

public void setValue(double value) {
this.value = value;
}
}```
```public interface Tax {
double calculate(Invoice invoice);
}```

— LOOK THIS WITH ATTENTION —

```public abstract class TemplateConditionalInvoice implements Tax {

public double calculate(Invoice invoice) {

if(isToApplyMaximunRate(invoice)) {
return applyMaximumRate(invoice);
} else {
return applyMinimumRate(invoice);
}
}

protected abstract boolean isToApplyMaximunRate(Invoice invoice);
protected abstract double applyMaximumRate(Invoice invoice);
protected abstract double applyMinimumRate(Invoice invoice);
}```

## DECORATOR

When ?

Whenever we realize we have behaviors that can be composed of behaviors involved other classes in the same hierarchy.”Behaviors comprise other behaviors.”

Diagram:

Example:

```public class DecoratorTest {

@Test
public void testDecorator() {
Tax taxComplexy = new CityTax(new FederalTax());
Invoice invoice = new Invoice(1000.0);
double result = taxComplexy.calculate(invoice);
TestCase.assertEquals(result, 150);
}
}```
```public abstract class Tax {

private final Tax otherTax;

public Tax(Tax otherTax) {
this.otherTax = otherTax;
}

// construtor default
public Tax() {
this.otherTax = null;
}

protected double calculateOtherTax(Invoice invoice) {
// If don't exist exist
if(otherTax == null) return 0;
return otherTax.calculate(invoice);
}

public abstract double calculate(Invoice invoice);

}```
```public class FederalTax extends Tax {

public FederalTax(Tax otherTax) {
super(otherTax);
}

public FederalTax(){}

@Override
public double calculate(Invoice invoice) {
return invoice.getValue() * 0.05 + this.calculateOtherTax(invoice);
}

}```
```public class CityTax extends Tax {

public CityTax(Tax otherTax) {
super(otherTax);
}

public CityTax(){}

@Override
public double calculate(Invoice invoice) {
return invoice.getValue() * 0.1 + this.calculateOtherTax(invoice);
}
}```
```public class Invoice {

private double value;

public Invoice(double value) {
this.value = value;
}

public double getValue() {
return value;
}

private void setValue(double value) {
this.value = value;
}
}```

## STATE

When ?

When we have actions to be performed according to the states.

Diagram :

Example:

Problem :

If the state order is in progress apply 10% of discount;

If the state order is in approved apply 5% of discount;

```@Test
public void testDiscountExtra(){
Order order = new Order(100.0);

// Apply 10% discount because the state is Progress
order.applyDiscountExtra();
TestCase.assertEquals(order.value, 90.0);
// Aprove Order
order.approve();
// Apply 5% discount because the state is Progress
order.applyDiscountExtra();
TestCase.assertEquals(order.value, 85.5);
order.finish();

// If you call now applyDiscountExtra()
// you will receive a RunTimeException

try{
order.applyDiscountExtra();
}catch (RuntimeException r){
TestCase.assertTrue(true);
}
}```
```public class Order {

protected double value;
protected OrderState currentState; // veja a mudança aqui

public Order(double value) {
this.value = value;
this.currentState = new OrderProgress();
}

public void applyDiscountExtra() {
currentState.applyDiscountExtra(this);
}

public void approve() {
currentState.approve(this);
}

public void refuse() {
currentState.refuse(this);
}

public void finish() {
currentState.finish(this);
}

public double getValue() {
return value;
}

public void setValue(double value) {
this.value = value;
}

public OrderState getCurrentState() {
return currentState;
}

public void setCurrentState(OrderState currentState) {
this.currentState = currentState;
}
}

```
```public interface OrderState {
void applyDiscountExtra(Order order);
void approve(Order order);
void refuse(Order order);
void finish(Order order);
}```
```public class OrderApproved implements OrderState {

@Override
public void applyDiscountExtra(Order order) {
order.value -= order.value * 0.05;
}

@Override
public void approve(Order order) {
order.currentState = new OrderApproved();
}

@Override
public void refuse(Order order) {
order.currentState = new OrderRefused();
}

@Override
public void finish(Order order) {
order.currentState = new OrderFinish();
}
}```
```ublic class OrderFinish implements OrderState {
@Override
public void applyDiscountExtra(Order order) {
new RuntimeException("Order finished");
}

@Override
public void approve(Order order) {
new RuntimeException("Order finished");
}

@Override
public void refuse(Order order) {
new RuntimeException("Order finished");
}

@Override
public void finish(Order order) {
order.currentState = new OrderFinish();
}
}```
```public class OrderProgress implements OrderState {
@Override
public void applyDiscountExtra(Order order) {
order.value -= order.value * 0.1;
}

@Override
public void approve(Order order) {
order.currentState = new OrderApproved();
}

@Override
public void refuse(Order order) {
order.currentState = new OrderRefused();
}

@Override
public void finish(Order order) {
throw new RuntimeException("Order in progress");

}
}```
```public class OrderRefused implements OrderState {
@Override
public void applyDiscountExtra(Order order) {
new RuntimeException("Order refused");
}

@Override
public void approve(Order order) {
new RuntimeException("Order refused");
}

@Override
public void refuse(Order order) {
order.currentState = new OrderRefused();
}

@Override
public void finish(Order order) {
new RuntimeException("Order refused");
}
}```

## Builder

When ?

Whenever we have a complex object to be created, which it has several attributes or a complicated creation logic, we can centralize all in a Builder.

Example :

Problem : Create a invoice with a complex logic.

Solution:

Result/Cosole

*******************INVOICE**********************
Invoice Date Emission :09/06/2016
Invoice Date :09/06/2016
*******************ITEMS**********************
-ITEM A \$20.0
-ITEM B \$25.0
-ITEM C \$4.0
-ITEM D \$8.5
Total Items :57.5
*******************DISCOUNTS**********************
-B2B – 10.0%
-Week Promotion – 5.0%
Total Porcentagem :15.0%
*******************OBSERVATIONS********************
Order Late
*************************************************
Total Discount: \$15.0
Total Value: \$48.875
Date to Pay: 14/06/2016

Code :

```@Test
public void builderTest(){
LocalDate yesteday = LocalDate.now().minus(1, ChronoUnit.DAYS);

BuilderInvoice invoice = new BuilderInvoice();
.changeDateOrder(yesteday)
.close()
.emission();

TestCase.assertFalse(true);
}

```
```public class BuilderInvoice {

private Invoice invoice = new Invoice();

public BuilderInvoice() {
invoice.setDate(LocalDate.now());
invoice.setOrder(new Order());
invoice.getOrder().setDate(invoice.getDate());
}

public BuilderInvoice addItem(String name, double value) {
return this;
}

public BuilderInvoice addDiscount(String desc, double por) {
return this;
}

public BuilderInvoice changeDateOrder(LocalDate date) {
invoice.getOrder().setDate(date);
return this;
}

invoice.getOrder().setObservations(obs);
return this;
}

public BuilderInvoice close(){
double valueDiscount = (invoice.getOrder().getTotalValue() * invoice.getTotalDisountPorcentage())/100;
double totalValue =  invoice.getOrder().getTotalValue() - valueDiscount;
invoice.setTotalInvoice(totalValue);
invoice.setFinishDate(LocalDate.now());
invoice.setDatePayment(invoice.getFinishDate().plus(5, ChronoUnit.DAYS));
return this;
}

public void emission(){
System.out.println("*******************INVOICE**********************");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
System.out.println("Invoice Date Emission :" + this.invoice.getFinishDate().format(formatter) );
System.out.println("Invoice Date :" + this.invoice.getDate().format(formatter) );
System.out.println("*******************ITEMS**********************");
this.invoice.getOrder().getItemList().stream().forEach(i->{
System.out.println("-" + i.getName() + " \$" + i.getValue());
});
System.out.println("Total Items :" + this.invoice.getOrder().getTotalValue() );
System.out.println("*******************DISCOUNTS**********************");
this.invoice.getDiscountList().stream().forEach(i->{
System.out.println("-" + i.getDescription() + " - " + i.getPorcent() + "%");
});
System.out.println("Total Porcentagem :" + this.invoice.getTotalDisountPorcentage()  + "%" );
System.out.println("*******************OBSERVATIONS********************");
System.out.println( this.invoice.getOrder().getObservations());
System.out.println("*************************************************");
System.out.println("Total Discount: \$"+ this.invoice.getTotalDiscount());
System.out.println("Total Value: \$"+ this.invoice.getTotalInvoice());
System.out.println("Date to Pay: "+ this.invoice.getDatePayment().format(formatter));
}

}

```
```public class Invoice {

private Order order;
private double totalItens;
private List<Discount> discountList;
private double totalInvoice;
private LocalDate date;
private LocalDate datePayment;
private LocalDate finishDate;

public Invoice() {
this.discountList = new ArrayList<>();
this.discountList = new ArrayList<>();
}

public LocalDate getFinishDate() {
return finishDate;
}

public void setFinishDate(LocalDate finishDate) {
this.finishDate = finishDate;
}

public Double getTotalDisountPorcentage(){
return this.getDiscountList().stream().mapToDouble(i->i.getPorcent()).sum();
}

public List<Discount> getDiscountList() {
return discountList;
}

private void setDiscountList(List<Discount> discountList) {
this.discountList = discountList;
}

public LocalDate getDate() {
return date;
}

public void setDate(LocalDate date) {
this.date = date;
}

public LocalDate getDatePayment() {
return datePayment;
}

public void setDatePayment(LocalDate datePayment) {
this.datePayment = datePayment;
}

public Order getOrder() {
return order;
}

public void setOrder(Order order) {
this.order = order;
}

public double getTotalItens() {
}

private void setTotalItens(double totalItens) {
this.totalItens = totalItens;
}

public double getTotalDiscount() {
return this.getDiscountList().stream().mapToDouble( d-> d.getPorcent()).sum();
}

public double getTotalInvoice() {
}

public void setTotalInvoice(double totalInvoice) {
this.totalInvoice = totalInvoice;
}
}```
```public class Order {
private List<Item> itemList;
private LocalDate date;
private Double totalValue;
private String observations;

public Order(){
date = LocalDate.now();
this.itemList = new ArrayList<>();
}

public String getObservations() {
return observations;
}

public void setObservations(String observations) {
this.observations = observations;
}

public List<Item> getItemList() {
return itemList;
}

public void setItemList(List<Item> itemList) {
this.itemList = itemList;
}

public LocalDate getDate() {
return date;
}

public void setDate(LocalDate date) {
this.date = date;
}

public Double getTotalValue() {
return this.getItemList().stream().mapToDouble(i->i.getValue()).sum();
}

private void setTotalValue(Double totalValue) {
this.totalValue = totalValue;
}
}```
```public class Item {
private String name;
private double value;

private Item() {
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getValue() {
return value;
}

public void setValue(double value) {
this.value = value;
}
}

```
```public class Discount {
private String description;
private double porcent;

public Discount(String description, double porcent) {
this.description = description;
this.porcent = porcent;
}

public String getDescription() {
return description;
}

private void setDescription(String description) {
this.description = description;
}

public double getPorcent() {
return porcent;
}

private void setPorcent(double porcent) {
this.porcent = porcent;
}
}```

## Observer

When ?

When we have several different actions to be performed after a certain process.

Diagram :

Example :

Problem : After close an invoice you need do:

• Persist in database;
• Print
• Send email;
• Send SMS;

Solution :

Result/Console:

-> Persist in the database
*******************INVOICE**********************
Invoice Date Emission :09/06/2016
Invoice Date :09/06/2016
*******************ITEMS**********************
-ITEM A \$20.0
-ITEM B \$25.0
-ITEM C \$4.0
-ITEM D \$8.5
Total Items :57.5
*******************DISCOUNTS**********************
-B2B – 10.0%
-Week Promotion – 5.0%
Total Porcentagem :15.0%
*******************OBSERVATIONS********************
Order Late
*************************************************
Total Discount: \$15.0
Total Value: \$48.875
Date to Pay: 14/06/2016
-> Send email
-> Send Sms

Code:

```public class ObserverTest {

@Test
public void builderTest(){

BuilderInvoice invoice = new BuilderInvoice();

.close();

TestCase.assertFalse(true);
}
}

```
```public interface ActionsAfterCloserInvoice {

public void execute(Invoice invoice);
}

```
```public class EmailDAO implements ActionsAfterCloserInvoice {

public void execute(Invoice invoice){
System.out.println("-> Persist in the database");
// Here the implementation to persist in the database
}
}

```
```public class SenderEmail implements ActionsAfterCloserInvoice {

public void execute(Invoice invoice){
// Here the implementation to send email
System.out.println("-> Send email");
}
}

```
```public class SendSMS implements ActionsAfterCloserInvoice {

public void execute(Invoice invoice){
// Here the implementation to send a sms
System.out.println("-> Send Sms");
}
}

```
```public class Printer implements ActionsAfterCloserInvoice {

public void execute(Invoice invoice){
System.out.println("*******************INVOICE**********************");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
System.out.println("Invoice Date Emission :" + invoice.getFinishDate().format(formatter) );
System.out.println("Invoice Date :" + invoice.getDate().format(formatter) );
System.out.println("*******************ITEMS**********************");
invoice.getOrder().getItemList().stream().forEach(i->{
System.out.println("-" + i.getName() + " \$" + i.getValue());
});
System.out.println("Total Items :" + invoice.getOrder().getTotalValue() );
System.out.println("*******************DISCOUNTS**********************");
invoice.getDiscountList().stream().forEach(i->{
System.out.println("-" + i.getDescription() + " - " + i.getPorcent() + "%");
});
System.out.println("Total Porcentagem :" + invoice.getTotalDisountPorcentage()  + "%" );
System.out.println("*******************OBSERVATIONS********************");
System.out.println( invoice.getOrder().getObservations());
System.out.println("*************************************************");
System.out.println("Total Discount: \$"+ invoice.getTotalDiscount());
System.out.println("Total Value: \$"+ invoice.getTotalInvoice());
System.out.println("Date to Pay: "+ invoice.getDatePayment().format(formatter));
}
}

```
```public class BuilderInvoice {

private Invoice invoice ;
private List<ActionsAfterCloserInvoice> actionsAfterCloserInvoices ;
public BuilderInvoice() {
actionsAfterCloserInvoices = new ArrayList<>();
invoice = new Invoice();
invoice.setDate(LocalDate.now());
invoice.setOrder(new Order());
invoice.getOrder().setDate(invoice.getDate());
}

public BuilderInvoice addItem(String name, double value) {
return this;
}

public BuilderInvoice addDiscount(String desc, double por) {
return this;
}

public BuilderInvoice changeDateOrder(LocalDate date) {
invoice.getOrder().setDate(date);
return this;
}

invoice.getOrder().setObservations(obs);
return this;
}

public BuilderInvoice close(){
double valueDiscount = (invoice.getOrder().getTotalValue() * invoice.getTotalDisountPorcentage())/100;
double totalValue =  invoice.getOrder().getTotalValue() - valueDiscount;
invoice.setTotalInvoice(totalValue);
invoice.setFinishDate(LocalDate.now());
invoice.setDatePayment(invoice.getFinishDate().plus(5, ChronoUnit.DAYS));
actions();
return this;
}

// Here we call the actions --> observers
private void actions(){
actionsAfterCloserInvoices.stream().forEach(a-> a.execute(this.invoice));
}

return this;
}

}```

You also can check all implementations above in :

https://github.com/camilamacedo86/designPatternExamples