spring boot/기술 적용

Spring boot에 Facade 패턴 적용

ballde 2022. 10. 10. 13:08

Facade란?

"건물의 정면"을 의미로 어떤 소프트웨어의 다른 커다란 코드 부분에 대하여 간략화된 인터페이스를 제공해주는 디자인 패턴을 의미

class TV() {
    var channel: Int = 0
        set(value) {
            field = value
            println("Channel is set to $value")
        }
    var volume: Int = 0
        set(value) {
            field = value
            println("Volume is set to $value")
        }
}

class Remote() {
    fun on(tv: TV) {
        println("TV is on")
    }
    fun off(tv: TV) {
        println("TV is off")
    }
    fun setChannel(tv: TV, channel: Int) {
        tv.channel = channel
    }
    fun setVolume(tv: TV, volume: Int) {
        tv.volume = volume
    }
}

fun watchTv() {
    println("Watching TV")
    val tv = TV()
    val remote = Remote()
    remote.on(tv)
    remote.setChannel(tv, 5)
    remote.setVolume(tv, 10)
    remote.off(tv)
}
  • 사용자 입장에서 watchTv를 보려고 할 때 리모컨으로 티비를 키고 → 채널 올리고 → … → 리모컨으로 티비를 끈다.
  • 이러한 과정을 통해서 봐야한다. 퍼사드는 이런 사용자와 티비 사이의 간단한 이터페이스를 제공해주는 역할을 한다.
class Facade(val tv: TV, val remote: Remote) {
    fun watchTV() {
        remote.on(tv)
        remote.setChannel(tv, 5)
        remote.setVolume(tv, 10)
        remote.off(tv)
    }
}

fun watchTv() {
    val tv = TV()
    val remote = Remote()
    val facade = Facade(tv, remote)
    facade.watchTV()
}
  • 사용자 입장에서는 그 안의 서브 클래스들에 대해서는 알 필요가 없습니다.

퍼사드 패턴 적용

문제되는 코드

@RestController
@RequiredArgsConstructor
public class FacadeExController {

    private final FacadeExAService facadeExAService;

    @GetMapping("/api/v1/facade")
    public ApiResponse<String> facade() {
        facadeExAService.facadeA();
        return ApiResponse.OK;
    }

}

@Service
@RequiredArgsConstructor
public class FacadeExAService {

    private final FacadeExBService facadeExBService;

    public void facadeA() {
        facadeExBService.facadeB();
    }

}

@Service
@RequiredArgsConstructor
public class FacadeExBService {

    public void facadeB() {
        System.out.println("facade B");
    }

}
  • 우리가 service에 서비스 코드에서 service 코드를 부를 경우가 생길 수도 있다. ⇒ 이런경우 순환참조가 일어나서 문제가 될 수도 있다.(위에 코드에서 exA → exB 밖에 없어서 괜찮지만 exA → exB, exB → exA가 있을 경우 순환참조가 일어나게 된다. 이런경우 팀에서 약속을 통해서 막을 수는 있겠지만 어떤 상황이 발생할지 모르기 때문에 저런 상황을 만들지 않는게 좋다고 생각합니다.)

  • 퍼사드 패턴을 적용해서 위와 같은 패턴을 적용
@RestController
@RequiredArgsConstructor
public class FacadeExController {

    private final FacadeExFacade facadeExFacade;

    @GetMapping("/api/v1/facade")
    public ApiResponse<String> facade() {
        facadeExFacade.facade();
        return ApiResponse.OK;
    }

}

@Component
@RequiredArgsConstructor
public class FacadeExFacade {

    private final FacadeExAService facadeExAService;
    private final FacadeExBService facadeExBService;

    public void facade() {
        facadeExAService.facadeA();
        facadeExBService.facadeB();
    }

}