특정 요청이 여러 개의 dao 참조를 필요로 하는 경우가 존재한다고 가정하자.
이와 같은 경우, 우리는 service layer에 여러개의 dao를 필드로 둘 것인지, controller가 여러 개의 service를 가질 것인지, service가 여러 개의 서비스를 가지도록 할 것인지에 대해 고민하게 된다.
이 경우, 나는 Facade Pattern과 유사한 방식을 Service Layer에 적용해보았다. (물론 적용할 땐, 퍼사드인지 몰랐다!)
우선 Facade Pattern이란, 어떠한 서브 시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공하는 방법이다. 라고 했지만, 너무 어렵다. 실생활에서의 예를 들어보자면, 퍼사드는 건물의 정면(외관)을 의미하는데, 하위 시스템들에 대해 건물의 입구(퍼사드)를 제공하여 하위 시스템들로 접근하기 위해 건물의 입구를 통과하는 느낌?이랄까?
퍼사드가 적용된 코드 예시를 통해 한번 제대로 이해해보자. 참조한 예시는 아래 참조에 링크로 두었으니, 자세한 내용을 확인하고 싶다면 해당 링크를 참조하길!
도메인
public class Product {
public int productId;
public String name;
public Product(){}
public Product(int productId, String name){
this.productId=productId;
this.name=name;
}
}
Inventory Service
public class InventoryService {
public static boolean isAvailable(Product product){
/*Check Warehouse database for product availability*/
return true;
}
}
Payment Service
public class PaymentService {
public static boolean makePayment(){
/*Connect with payment gateway for payment*/
return true;
}
}
Shipping Service
public class ShippingService {
public static void shipProduct(Product product){
/*Connect with external shipment service to ship product*/
}
}
위의 3가지 서비스들을 하위 시스템 클래스라고 하자. 하위 시스템 클래스는 주문 이행 프로세스에 대한 다양한 서비스를 나타낸다. 여기서 주목해야할 점은 서브 시스템 클래스에서는 Facade에 대한 참조가 없다는 점이다. 각 서브 클래스는 Facade를 알고 있지 않으며 Facade가 존재하지 않더라도 독립적으로 작동하도록 설계되었다.
즉, 서브 시스템 클래스는 Facade에서 사용되지만, 그 반대는 아니다.
Order Service Facade
public interface OrderServiceFacade {
boolean placeOrder(int productId);
}
Order Service Facade Implements Class
public class OrderServiceFacadeImpl implements OrderServiceFacade{
public boolean placeOrder(int pId){
boolean orderFulfilled=false;
Product product=new Product();
product.productId=pId;
if(InventoryService.isAvailable(product))
{
System.out.println("Product with ID: "+ product.productId+" is available.");
boolean paymentConfirmed= PaymentService.makePayment();
if(paymentConfirmed){
System.out.println("Payment confirmed...");
ShippingService.shipProduct(product);
System.out.println("Product shipped...");
orderFulfilled=true;
}
}
return orderFulfilled;
}
}
Order Controller
public class OrderFulfillmentController {
OrderServiceFacade facade;
boolean orderFulfilled=false;
public void orderProduct(int productId) {
orderFulfilled=facade.placeOrder(productId);
System.out.println("OrderFulfillmentController: Order fulfillment completed. ");
}
}
아무튼 코드들로 퍼사드 패턴을 서비스에 적용한 방법에 대해서 나열만 해 보았는데, 요점은 다음과 같다.
컨트롤러에서는 Facade만을 필드로 활용하여 여러 서비스를 필요로 하는 요청을 전달할 수 있고,
Facade는 여러 서비스를 조합해 사용하며 필요한 기능을 가진 서비스들을 조합해 메서드를 구현할 수 있다.
그리고 하위 서비스 클래스들은 조합됨과 동시에 퍼사드와는 독립적으로 자신의 일을 수행할 수도 있다.
그리고, 하위 서비스 클래스들은 dao를 1:1로 매핑하여 가질 수 있으며 퍼사드는 dao를 알 필요가 없이 해당 서비스에 요청을 보냄으로서 결과를 응답받을 수 있다.
끗
참조
- https://springframework.guru/gang-of-four-design-patterns/facade-pattern/