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();
}
}
'spring boot > 기술 적용' 카테고리의 다른 글
Spring boot에 전략패턴 적용 (0) | 2022.10.10 |
---|---|
webClient 와 feignClient (0) | 2022.10.10 |
jpa comment를 custom annotation으로 만들기 (0) | 2022.07.20 |
stub, mock, spy 비교 (0) | 2022.07.02 |
converter를 만들지 않고 jpa mysql에서 json 사용하기 (0) | 2022.06.28 |