Files
.circleci
.github
.mvn
abstract-document
abstract-factory
active-object
acyclic-visitor
adapter
aggregator-microservices
ambassador
api-gateway
arrange-act-assert
async-method-invocation
balking
bridge
builder
business-delegate
bytecode
caching
callback
chain-of-responsibility
circuit-breaker
cloud-static-content-hosting
collection-pipeline
combinator
command
commander
composite
composite-entity
converter
cqrs
dao
data-bus
data-locality
data-mapper
data-transfer-object
decorator
delegation
dependency-injection
dirty-flag
domain-model
double-buffer
double-checked-locking
double-dispatch
eip-aggregator
eip-message-channel
eip-publish-subscribe
eip-splitter
eip-wire-tap
etc
event-aggregator
event-asynchronous
event-driven-architecture
event-queue
event-sourcing
execute-around
extension-objects
facade
factory
factory-kit
factory-method
fanout-fanin
feature-toggle
filterer
fluentinterface
flux
flyweight
front-controller
game-loop
guarded-suspension
half-sync-half-async
hexagonal
intercepting-filter
interpreter
iterator
layers
lazy-loading
leader-election
leader-followers
localization
lockable-object
marker
master-worker-pattern
mediator
memento
model-view-controller
model-view-presenter
model-view-viewmodel
module
monad
monitor
monostate
multiton
mute-idiom
naked-objects
null-object
object-mother
object-pool
observer
page-object
parameter-object
partial-response
pipeline
poison-pill
presentation
priority-queue
private-class-data
producer-consumer
promise
property
prototype
proxy
queue-load-leveling
reactor
reader-writer-lock
registry
repository
resource-acquisition-is-initialization
retry
role-object
saga
separated-interface
etc
src
README.md
pom.xml
servant
serverless
service-layer
service-locator
sharding
singleton
spatial-partition
special-case
specification
state
step-builder
strangler
strategy
subclass-sandbox
table-module
template-method
thread-pool
throttling
tls
tolerant-reader
trampoline
transaction-script
twin
typeobjectpattern
unit-of-work
update-method
value-object
version-number
visitor
.all-contributorsrc
.gitignore
CONTRIBUTING.MD
LICENSE.md
PULL_REQUEST_TEMPLATE.md
README.md
checkstyle-suppressions.xml
gpl-3.0.txt
lgpl-3.0.txt
license-plugin-header-style.xml
lombok.config
mvnw
mvnw.cmd
pom.xml
java-design-patterns/separated-interface/README.md

140 lines
4.2 KiB
Markdown
Raw Normal View History

---
layout: pattern
title: Separated Interface
folder: separated-interface
permalink: /patterns/separated-interface/
categories: Structural
language: en
tags:
- Decoupling
---
## Intent
2020-09-13 17:39:10 +03:00
Separate the interface definition and implementation in different packages. This allows the client
to be completely unaware of the implementation.
## Explanation
Real world example
2020-09-13 17:39:10 +03:00
> 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.
In plain words
2020-09-13 17:39:10 +03:00
> 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.
2020-09-13 17:39:10 +03:00
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).
**Programmatic Example**
2020-09-13 17:39:10 +03:00
**Client**
`InvoiceGenerator` class accepts the cost of the product and calculates the total
amount payable inclusive of tax.
```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);
}
}
```
2020-09-13 17:39:10 +03:00
The tax calculation logic is delegated to the `TaxCalculator` interface.
2020-09-13 17:39:10 +03:00
```java
public interface TaxCalculator {
double calculate(double amount);
}
```
**Implementation package**
2020-09-13 17:39:10 +03:00
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.
```java
public class ForeignTaxCalculator implements TaxCalculator {
public static final double TAX_PERCENTAGE = 60;
@Override
public double calculate(double amount) {
return amount * TAX_PERCENTAGE / 100.0;
}
}
```
2020-09-13 17:39:10 +03:00
Another is `DomesticTaxCalculator` which levies 20% tax for international products.
```java
public class DomesticTaxCalculator implements TaxCalculator {
public static final double TAX_PERCENTAGE = 20;
@Override
public double calculate(double amount) {
return amount * TAX_PERCENTAGE / 100.0;
}
}
```
2020-09-13 17:39:10 +03:00
These both implementations are instantiated and injected in the client class by the ```App.java```
class.
```java
var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTaxCalculator());
LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax());
var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTaxCalculator());
LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax());
```
## Class diagram
2020-09-13 17:39:10 +03:00
![alt text](./etc/class_diagram.png "Separated Interface")
## Applicability
2020-09-13 17:39:10 +03:00
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)
2020-09-13 17:39:10 +03:00
* [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)