Mediator Design Pattern juga memiliki nama lain, yaitu Controller atau Intermediary object karena tugasnya hanya sebagai penghubung antar dependency. Seperti Controller pada pola MVC yang isinya ga ada logic selain memanggil dependency object terkait. Mediator Design Pattern konsepnya seperti Orchestrator Saga Pattern pada distributed system, di mana terdapat satu komponen yang bertugas mengendalikan flow antar dependency secara terpusat.
Mediator Design Pattern adalah Behavioral Design Pattern yang bertugas sebagai pengatur flow antar dependency untuk mengurangi masalah dependency yang berantakan.
Design Pattern
Use Case
Kita akan menggunakan contoh kasus yang sama seperti pada contoh Observer Design Pattern, yaitu flow pemesanan barang, lalu generate invoice serta update stok. Tapi kali ini kita akan menggunakan pendekatan Mediator Design Pattern.
Contoh Code
Ordering Class
public class Ordering{
private String orderNo;
private String product;
private int totalItem;
private BigDecimal price;
private String seller;
private String customer;
public String getOrderNo(){
return orderNo;
}
public void setOrderNo(String orderNo){
this.orderNo = orderNo;
}
public String getProduct(){
return product;
}
public void setProduct(String product){
this.product = product;
}
public int getTotalItem(){
return totalItem;
}
public void setTotalItem(int totalItem){
this.totalItem = totalItem;
}
public BigDecimal getPrice(){
return price;
}
public void setPrice(BigDecimal price){
this.price = price;
}
public String getSeller(){
return seller;
}
public void setSeller(String seller){
this.seller = seller;
}
public String getCustomer(){
return customer;
}
public void setCustomer(String customer){
this.customer = customer;
}
}
InvoiceCreation Interface
public interface InvoiceCreation{
void create(Ordering ordering);
}
InvoiceCreationUseCase Class
public class InvoiceCreationUseCase implements InvoiceCreation{
@Override
public void create(Ordering ordering){
System.out.println("invoice from order " + ordering.getOrderNo() + " has been created");
}
}
StockUpdater Interface
public interface StockUpdater{
void update(Ordering ordering);
}
StockUpdaterUseCase Class
public class StockUpdaterUseCase implements StockUpdater{
@Override
public void update(Ordering ordering){
System.out.println("stock of product " + ordering.getProduct() + " from order " + ordering.getOrderNo() +
" has been updated " + ordering.getTotalItem() + " unit");
}
}
OrderCreation Interface
public interface OrderCreation{
Ordering createOrder();
}
OrderCreationUseCase Class
public class OrderCreationUseCase implements OrderCreation{
private final InvoiceCreation invoiceCreation;
private final StockUpdater stockUpdater;
public OrderCreationUseCase(InvoiceCreation invoiceCreation, StockUpdater stockUpdater){
this.invoiceCreation = invoiceCreation;
this.stockUpdater = stockUpdater;
}
@Override
public Ordering createOrder(){
Ordering ordering = new Ordering();
ordering.setCustomer("messi");
ordering.setPrice(BigDecimal.ONE);
ordering.setProduct("bola");
ordering.setSeller("ronaldo");
ordering.setTotalItem(5);
ordering.setOrderNo("xxx-001");
System.out.println("successfully created order " + ordering.getOrderNo());
invoiceCreation.create(ordering);
stockUpdater.update(ordering);
return ordering;
}
}
Contoh penggunaan
public static void main(String[] args){
OrderCreation orderCreation = new OrderCreationUseCase(new InvoiceCreationUseCase(), new StockUpdaterUseCase());
orderCreation.createOrder();
}
Masalah
Masalahnya mirip dengan Observer Design Pattern, bahwa dependencynya saling bergantung secara langsung. Sehingga kalau misalkan ada penambahan tentu akan membuat dependencynya membengkak dan perubahan flow akan dilakukan langsung pada class OrderCreationUseCase sehingga bisa melanggar Single Responsibility Principle. Ini bisa jadi code smell.
Solusi
Sekarang kita terapkan Mediator Design Pattern😎.
OrderCreationUseCase Class
public class OrderCreationUseCase implements OrderCreation{
@Override
public Ordering createOrder(){
Ordering ordering = new Ordering();
ordering.setCustomer("messi");
ordering.setPrice(BigDecimal.ONE);
ordering.setProduct("bola");
ordering.setSeller("ronaldo");
ordering.setTotalItem(5);
ordering.setOrderNo("xxx-001");
System.out.println("successfully created order " + ordering.getOrderNo());
return ordering;
}
}
OrderCreationMediator Interface
public interface OrderCreationMediator{
void execute();
}
OrderCreationMediatorImpl Class
public class OrderCreationMediatorImpl implements OrderCreationMediator{
private final OrderCreation orderCreation;
private final InvoiceCreation invoiceCreation;
private final StockUpdater stockUpdater;
OrderCreationMediatorImpl(OrderCreation orderCreation, InvoiceCreation invoiceCreation, StockUpdater stockUpdater){
this.orderCreation = orderCreation;
this.invoiceCreation = invoiceCreation;
this.stockUpdater = stockUpdater;
}
@Override
public void execute(){
Ordering order = orderCreation.createOrder();
invoiceCreation.create(order);
stockUpdater.update(order);
}
}
Contoh penggunaan
public static void main(String[] args){
OrderCreationMediator orderCreationMediator = new OrderCreationMediatorImpl(new OrderCreationUseCase(), new InvoiceCreationUseCase(), new StockUpdaterUseCase());
orderCreationMediator.execute();
}
Kita perlu menghapus dependency pada class OrderCreationUseCase. Kita juga menambahkan interface OrderCreationMediator beserta implementasinya. Di object Mediator itulah flownya diatur. Jadi antara OrderCreation, InvoiceCreation dan StockUpdater tidak ada dependency secara langsung. Melainkan berkomunikasi lewat Mediator. Mediator isinya ga ada logic selain mengontrol flow antar dependency object.
Kenapa menggunakan Mediator Design Pattern?
Mediator Design Pattern digunakan untuk mengurangi kompleksitas dependency antar objek. Proses komunikasi antar objek akan dihandle oleh class Mediator. Sehingga setiap ada perubahan flow dependency kita hanya perlu ubah pada class Mediator saja, bukan pada masing-masing object use case. Sehingga memenuhi kriteria Single Responsibility Principle. Tapi perlu diperhatikan juga, Mediator Design Pattern memiliki kelemahan seperti Façade Design Pattern, yaitu bila dependencynya makin banyak maka bakal jadi God Object. Jadi kalau dependencynya makin besar, perlu dipertimbangkan juga untuk memecah Mediator objeknya jadi beberapa Mediator yang lebih kecil.
Verdict
Mediator Design Pattern mengurangi kompleksitas dependency pada object use case melalui object independen yang mengatur flow antar dependency. Implementasinya seperti Controller pada pola MVC, di mana tidak ada business logic di dalamnya. Mediator Design Pattern penerapannya agak mirip Observer Design Pattern, karena sama-sama meminimalkan dependency antar objek. Akan tetapi pada Observer Design Pattern dependencynya dibikin general menjadi beberapa Subscriber dari suatu object dan dapat diubah saat runtime, sedangkan pada Mediator Design Pattern dependencynya dipindah ke Mediator dan tidak dapat diubah saat runtime. Jika Observer Design Pattern konsepnya seperti Choreography Saga Pattern yang mana Publisher akan menginfokan suatu event ke semua Subscriber, maka Mediator Design Pattern konsepnya seperti Orchestrator Saga Pattern di mana object yang bertugas sebagai Mediator menjadi pusat komunikasi antar dependency. Tugasnya juga memiliki kesamaan dengan Façade Design Pattern untuk mengurangi kompleksitas pada object dengan logic seminimal mungkin. Hanya saja pada Façade Design Pattern tujuannya kita menyederhanakan system agar penggunaannya lebih straightforward, sedangkan Mediator Design Pattern tugasnya lebih spesifik hanya menjadi pengatur flow dependency suatu use case.