README.md 4.2 KB
Newer Older
1 2 3 4 5
---
layout: pattern
title: Separated Interface
folder: separated-interface
permalink: /patterns/separated-interface/
6
categories: Structural
7 8 9 10 11 12
tags:
 - Decoupling
---


## Intent
I
Ilkka Seppälä 已提交
13 14 15

Separate the interface definition and implementation in different packages. This allows the client 
to be completely unaware of the implementation.
16 17 18 19 20

## Explanation

Real world example

I
Ilkka Seppälä 已提交
21 22
> An Invoice generator may be created with ability to use different Tax calculators that may be 
> added in the invoice depending upon type of purchase, region etc.         
23 24 25

In plain words

I
Ilkka Seppälä 已提交
26 27
> Separated interface pattern encourages to keep the implementations of an interface decoupled from 
> the client and its definition, so the client is not dependent on the implementation.
28

I
Ilkka Seppälä 已提交
29 30 31 32 33 34
A client code may abstract some specific functionality to an interface, and define the definition of 
the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface) 
is an API intended and open to be implemented or extended by a third party). Another package may 
implement this interface definition with a concrete logic, which will be injected into the client 
code at runtime (with a third class, injecting the implementation in the client) or at compile time 
(using Plugin pattern with some configurable file).
35 36 37

**Programmatic Example**

I
Ilkka Seppälä 已提交
38 39 40 41
**Client** 

`InvoiceGenerator` class accepts the cost of the product and calculates the total 
amount payable inclusive of tax.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

```java
public class InvoiceGenerator {

  private final TaxCalculator taxCalculator;

  private final double amount;

  public InvoiceGenerator(double amount, TaxCalculator taxCalculator) {
    this.amount = amount;
    this.taxCalculator = taxCalculator;
  }

  public double getAmountWithTax() {
    return amount + taxCalculator.calculate(amount);
  }

}
```

I
Ilkka Seppälä 已提交
62
The tax calculation logic is delegated to the `TaxCalculator` interface.
63

I
Ilkka Seppälä 已提交
64
```java
65 66 67 68 69 70 71 72
public interface TaxCalculator {

  double calculate(double amount);

}
```

**Implementation package**
I
Ilkka Seppälä 已提交
73 74 75 76 77

In another package (which the client is completely unaware of) there exist multiple implementations 
of the `TaxCalculator` interface. `ForeignTaxCalculator` is one of them which levies 60% tax 
for international products.

78
```java
79
public class ForeignTaxCalculator implements TaxCalculator {
80 81 82 83 84 85 86 87 88 89 90

  public static final double TAX_PERCENTAGE = 60;

  @Override
  public double calculate(double amount) {
    return amount * TAX_PERCENTAGE / 100.0;
  }

}
```

I
Ilkka Seppälä 已提交
91 92
Another is `DomesticTaxCalculator` which levies 20% tax for international products.

93
```java
94
public class DomesticTaxCalculator implements TaxCalculator {
95 96 97 98 99 100 101 102 103 104 105

  public static final double TAX_PERCENTAGE = 20;

  @Override
  public double calculate(double amount) {
    return amount * TAX_PERCENTAGE / 100.0;
  }

}
```

I
Ilkka Seppälä 已提交
106 107
These both implementations are instantiated and injected in the client class by the ```App.java``` 
class.
108 109

```java
110
    var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTaxCalculator());
111 112 113

    LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax());

114
    var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTaxCalculator());
115 116 117 118 119

    LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax());
```

## Class diagram
I
Ilkka Seppälä 已提交
120

121 122 123
![alt text](./etc/class_diagram.png "Separated Interface")

## Applicability
I
Ilkka Seppälä 已提交
124

125 126 127 128 129 130 131 132 133 134 135 136 137
Use the Separated interface pattern when

* You are developing a framework package, and your framework needs to call some application code through interfaces.
* You have separate packages implementing the functionalities which may be plugged in your client code at runtime or compile-time.
* Your code resides in a layer that is not allowed to call the interface implementation layer by rule. For example, a domain layer needs to call a data mapper.

## Tutorial 

* [Separated Interface Tutorial](https://www.youtube.com/watch?v=d3k-hOA7k2Y)

## Credits

* [Martin Fowler](https://www.martinfowler.com/eaaCatalog/separatedInterface.html)
I
Ilkka Seppälä 已提交
138
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=e08dfb7f2cf6153542ef1b5a00b10abc)