Facade

seokseungminยท2024๋…„ 11์›” 15์ผ

Today I Learned

๋ชฉ๋ก ๋ณด๊ธฐ
17/20
post-thumbnail

๐Ÿ“š

Facade Pattern (ํผ์‚ฌ๋“œ ํŒจํ„ด)


Facade Pattern์ด๋ž€?

ํผ์‚ฌ๋“œ ํŒจํ„ด(Facade Pattern)์€ ๊ตฌ์กฐ ํŒจํ„ด(Structural Pattern)์˜ ํ•œ ์ข…๋ฅ˜๋กœ, ๋ณต์žกํ•œ ์„œ๋ธŒ ์‹œ์Šคํ…œ์˜ ๊ธฐ๋Šฅ๋“ค์„ ๊ฐ„๋‹จํ•œ ์ƒ์œ„ ์ˆ˜์ค€์˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ œ๊ณตํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ธŒ ์‹œ์Šคํ…œ ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ค„์ด๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๋Š” ๋‚ด๋ถ€์˜ ๋ณต์žกํ•œ ๋กœ์ง์— ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ ๋„, ๋‹จ์ˆœํ™”๋œ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ํ•„์š”ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Facade Pattern์˜ ํŠน์ง•

  1. ๋‚ฎ์€ ๊ฒฐํ•ฉ๋„
    ํด๋ผ์ด์–ธํŠธ๋Š” ํผ์‚ฌ๋“œ ๊ฐ์ฒด๋งŒ ์•Œ๋ฉด ๋˜๋ฏ€๋กœ ์„œ๋ธŒ ์‹œ์Šคํ…œ์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์— ์˜์กดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  2. ๊ฐ€๋…์„ฑ ์ฆ๊ฐ€
    ํด๋ผ์ด์–ธํŠธ์—์„œ ์—ฌ๋Ÿฌ ์„œ๋ธŒ ์‹œ์Šคํ…œ์„ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹ , ๋‹จ์ผ ํผ์‚ฌ๋“œ ๊ฐ์ฒด๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.

  3. ์„œ๋ธŒ ์‹œ์Šคํ…œ ์ง์ ‘ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    ํ•„์š”์— ๋”ฐ๋ผ ์„œ๋ธŒ ์‹œ์Šคํ…œ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ์ง€๊ฐ€ ์œ ์—ฐํ•ด์ง‘๋‹ˆ๋‹ค.


์ฐธ๊ณ : ์ œ๋ฏธ๋‹ˆ์˜ ๊ฐœ๋ฐœ์‹ค๋ฌด

๊ธฐ์กด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ 

๊ธฐ์กด ๋ฐฉ์‹์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ "๋‚˜์˜ ํšŒ์› ์ •๋ณด ์กฐํšŒ"์™€ "๋‹ค๋ฅธ ํšŒ์› ์ •๋ณด ์กฐํšŒ"๋ฅผ ์š”์ฒญํ•  ๋•Œ, ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ ๋ณ„๋„๋กœ DTO๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” ๋น„์Šทํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ์„œ๋น„์Šค ๋กœ์ง์ด ์ค‘๋ณต๋˜๊ณ  ํ™•์žฅ์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ณ€๊ฒฝํ•œ ๊ตฌ์กฐ ์‰ฌ์šด ์ดํ•ด๋„

๊ธฐ์กด ๊ตฌ์กฐ
  1. ์ปจํŠธ๋กค๋Ÿฌ์˜ ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฐฉ์‹
// UserController์˜ ๊ธฐ์กด ๋ฐฉ์‹
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/users")
public class UserController {

    private final UserService userService;

    // ๋‚˜์˜ ํšŒ์›์ •๋ณด ์กฐํšŒ
    @GetMapping
    public ResponseEntity<?> getUserInfo(Authentication authentication) {
        return ResponseEntity.status(OK)
            .body(ResponseMessage.success(userService.getUserInfo(getCurrentUser(authentication))));
    }

    // ๋‹ค๋ฅธ ํšŒ์› ์ •๋ณด ์กฐํšŒ
    @GetMapping("/{userId}")
    public ResponseEntity<?> getOtherUserInfo(@PathVariable Long userId) {
        return ResponseEntity.status(OK)
            .body(ResponseMessage.success(userService.getOtherUserInfo(userId)));
    }

    private UserEntity getCurrentUser(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new BizException(UNAUTHORIZED_ERROR);
        }
        return userRepository.findByEmail(((CustomUserDetails) authentication.getPrincipal()).getUsername())
            .orElseThrow(() -> new BizException(USER_NOT_FOUND_ERROR));
    }
}
  1. UserService์˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹
@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    // ๋‚˜์˜ ํšŒ์›์ •๋ณด ์กฐํšŒ ๋กœ์ง
    public UserInfoResponseDTO getUserInfo(UserEntity currentUser) {
        return UserInfoResponseDTO.builder()
            .id(currentUser.getId())
            .username(currentUser.getUsername())
            .nickname(currentUser.getNickname())
            .phone(currentUser.getPhone())
            .email(currentUser.getEmail())
            .status(currentUser.getStatus())
            .build();
    }

    // ๋‹ค๋ฅธ ํšŒ์› ์ •๋ณด ์กฐํšŒ ๋กœ์ง
    public OtherUserInfoResponseDTO getOtherUserInfo(Long userId) {
        UserEntity userEntity = userRepository.findById(userId)
        .orElseThrow(()->new BizException(USER_NOT_FOUND_ERROR));
      
        return OtherUserInfoResponseDTO.builder()
            .username(userEntity.getUsername())
            .nickname(userEntity.getNickname())
            .email(userEntity.getEmail())
            .status(userEntity.getStatus())
            .build();
    }
}
๋ฌธ์ œ์ 
  1. ์ค‘๋ณต๋œ ๋กœ์ง

    • UserService์—์„œ "๋‚˜์˜ ํšŒ์› ์ •๋ณด ์กฐํšŒ"์™€ "๋‹ค๋ฅธ ํšŒ์› ์ •๋ณด ์กฐํšŒ" ๋กœ์ง์ด ๊ฑฐ์˜ ๋™์ผํ•˜์ง€๋งŒ, ๋ณ„๋„์˜ DTO๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ๋ฒˆ ์ž‘์„ฑ๋จ.
    • ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋‚ฎ์Œ.
  2. ํ™•์žฅ์„ฑ ๋ฌธ์ œ

    • ํด๋ผ์ด์–ธํŠธ ์š”๊ตฌ์— ๋”ฐ๋ผ ์ถ”๊ฐ€์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ, ๊ฐ ์„œ๋น„์Šค ๋กœ์ง์— ์ƒˆ๋กœ์šด ์ฝ”๋“œ๊ฐ€ ํ•„์š”.
  3. ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋ณต์žก์„ฑ

    • ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ์„ธ๋ถ€ ๋กœ์ง์ด ๋…ธ์ถœ๋˜์–ด ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Œ.

Facade Pattern ์ ์šฉ ํ›„ ๊ฐœ์„ ๋œ ๊ตฌ์กฐ

๊ฐœ์„ ๋œ ๊ตฌ์กฐ

๊ณตํ†ต ๋ฐ์ดํ„ฐ๋Š” ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ ,
Facade ๋ ˆ์ด์–ด์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์— ๋งž๊ฒŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ์„œ๋น„์Šค ๋กœ์ง์˜ ์ค‘๋ณต ์ œ๊ฑฐ์™€ ํ™•์žฅ์„ฑ ํ–ฅ์ƒ์„ ๋™์‹œ์— ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Facade ๊ตฌํ˜„ ์ฝ”๋“œ
@Service
@Slf4j
@RequiredArgsConstructor
public class UserInfoFacade {

    private final UserParticipationService userParticipationService;
    private final UserService userService;
    private final RedisTemplate<String, Object> redisTemplate;

    public UserInfoFacadeDto getUserInfo(Long userId) {
        String cacheKey = "userInfo:" + userId;

        // Redis์—์„œ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
        Object cachedData = redisTemplate.opsForValue().get(cacheKey);
        if (cachedData != null) {
            log.info("Cache hit for user ID: {}", userId);
            return (UserInfoFacadeDto) cachedData;
        }
        UserServiceDto userInfo = userService.getUserInfo(userId);

        Integer completedTripsCount = userParticipationService.getCompletedTripsCount(
            String.valueOf(userId));

        UserInfoFacadeDto build = UserInfoFacadeDto.builder()
            .id(userInfo.getId())
            .count(completedTripsCount)
            .username(userInfo.getUsername())
            .phone(userInfo.getPhone())
            .email(userInfo.getEmail())
            .mbti(userInfo.getMbti())
            .ratingAvg(userInfo.getRatingAvg())
            .birth(userInfo.getBirth())
            .introduction(userInfo.getIntroduction())
            .nickname(userInfo.getNickname())
            .status(userInfo.getStatus())
            .smoking(userInfo.getSmoking())
            .gender(userInfo.getGender())
            .build();

        // Redis์— ์บ์‹œ ์ €์žฅ (๋งŒ๋ฃŒ ์‹œ๊ฐ„ 1์‹œ๊ฐ„ ์„ค์ •)
        redisTemplate.opsForValue().set(cacheKey, build, 1, TimeUnit.HOURS);
        log.info("Cache miss for user ID: {}. Data cached.", userId);

        return build;
    }
}

UserService์˜ getUserInfo

 public UserServiceDto getUserInfo(long userId) {
        UserEntity userEntity = userRepository.findById(userId).orElseThrow(()->new BizException(USER_NOT_FOUND_ERROR));
        ProfileEntity profileEntity = profileRepository.findByUserId(userEntity.getId())
            .orElseThrow(() -> new BizException(PROFILE_NOT_FOUND_ERROR));

        // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์กฐํšŒ
        UserServiceDto userInfo = UserServiceDto.builder()
            .id(userEntity.getId())
            .username(userEntity.getUsername())
            .nickname(userEntity.getNickname())
            .phone(userEntity.getPhone())
            .email(userEntity.getEmail())
            .status(userEntity.getStatus())
            .introduction(profileEntity.getIntroduction())
            .mbti(profileEntity.getMbti())
            .gender(profileEntity.getGender())
            .smoking(profileEntity.getSmoking())
            .birth(profileEntity.getBirth())
            .ratingAvg(profileEntity.getRatingAvg())
            .build();

        return userInfo;
    }
์ปจํŠธ๋กค๋Ÿฌ์—์„œ Facade ํ˜ธ์ถœ
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/users")
public class UserController {

    private final UserInfoFacade userInfoFacade;

    // ๋‚˜์˜ ํšŒ์›์ •๋ณด ์กฐํšŒ
    @GetMapping
    public ResponseEntity<ResponseMessage<UserInfoResponseDTO>> getUserInfo(
        Authentication authentication) {
        UserInfoFacadeDto otherUserInfo = userInfoFacade.getUserInfo(getCurrentUser(authentication).getId());
        return ResponseEntity.status(OK)
            .body(ResponseMessage.success(UserInfoResponseDTO.fromDto(otherUserInfo)));
    }

    // ๋‹ค๋ฅธ ํšŒ์› ์ •๋ณด ์กฐํšŒ
    @GetMapping("/{userId}")
    public ResponseEntity<ResponseMessage<OtherUserInfoResponseDTO>> getOtherUserInfo(
        @PathVariable Long userId) {

        UserInfoFacadeDto otherUserInfo = userInfoFacade.getUserInfo(userId);
        return ResponseEntity.status(OK)
            .body(ResponseMessage.success(OtherUserInfoResponseDTO.fromDto(otherUserInfo)));
    }

UserInfoResponseDTO

@Data
@Builder
@Getter
@AllArgsConstructor
@JsonDeserialize(builder = UserInfoResponseDTO.UserInfoResponseDTOBuilder.class)
public class UserInfoResponseDTO {

    private Long id;
    private String username;
    private String nickname;
    private String phone;
    private String email;
    private String status;
    private MBTI mbti;
    private String smoking;
    private String introduction;
    private String gender;

    @JsonSerialize(using = LocalDateSerializer.class)
    @JsonDeserialize(using = LocalDateDeserializer.class)
    private LocalDate birth;
    private Double ratingAvg;

    public static UserInfoResponseDTO fromDto(UserInfoFacadeDto userInfoFacadeDto) {
        return UserInfoResponseDTO.builder()
            .id(userInfoFacadeDto.getId())
            .username(userInfoFacadeDto.getUsername())
            .nickname(userInfoFacadeDto.getNickname())
            .phone(userInfoFacadeDto.getPhone())
            .email(userInfoFacadeDto.getEmail())
            .mbti(userInfoFacadeDto.getMbti())
            .introduction(userInfoFacadeDto.getIntroduction())
            .birth(userInfoFacadeDto.getBirth())
            .ratingAvg(userInfoFacadeDto.getRatingAvg())
            .smoking(userInfoFacadeDto.getSmoking().getSmoke())
            .gender(userInfoFacadeDto.getGender().getGender())
            .status(userInfoFacadeDto.getStatus().getStatus())
            .build();
    }

    @JsonPOJOBuilder(withPrefix = "")
    public static class UserInfoResponseDTOBuilder {

    }
}

OtherUserInfoResponseDTO

@Builder
@Getter
@AllArgsConstructor
@JsonDeserialize(builder = OtherUserInfoResponseDTO.OtherUserInfoResponseDTOBuilder.class)
public class OtherUserInfoResponseDTO {

    private String username;
    private String nickname;
    private String email;
    private Integer count; // ์—ฌํ–‰ ํšŸ์ˆ˜
    private Double ratingAvg;
    private String gender;
    private String status;

    public static OtherUserInfoResponseDTO fromDto(UserInfoFacadeDto userInfoFacadeDto) {
        return OtherUserInfoResponseDTO.builder()
            .username(userInfoFacadeDto.getUsername())
            .nickname(userInfoFacadeDto.getNickname())
            .email(userInfoFacadeDto.getEmail())
            .count(userInfoFacadeDto.getCount())
            .ratingAvg(userInfoFacadeDto.getRatingAvg())
            .gender(userInfoFacadeDto.getGender().getGender())
            .status(userInfoFacadeDto.getStatus().getUserStatus())
            .build();
    }

    @JsonPOJOBuilder(withPrefix = "")
    public static class OtherUserInfoResponseDTOBuilder {

    }
}
FeignClient ํ™œ์šฉ
@Service
@RequiredArgsConstructor
public class UserParticipationService {

    private final TravelClient travelClient;

    public Integer getCompletedTripsCount(String userId) {
        ResponseEntity<Integer> response = travelClient.getParticipationsCompletedByUserId(userId);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new BizException(INTERNAL_SERVER_ERROR);
        }
    }
}

์ ์šฉ ํ›„ ์žฅ์ 

  1. ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€

    • Facade ๋ ˆ์ด์–ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜๋ฏ€๋กœ, ๊ณตํ†ต ๋กœ์ง์€ ์„œ๋น„์Šค์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ถ”๊ฐ€ ๋กœ์ง๋งŒ Facade์—์„œ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ.
  2. ์ค‘๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ

    • ๊ธฐ์กด์˜ "๋‚˜์˜ ํšŒ์› ์ •๋ณด ์กฐํšŒ"์™€ "๋‹ค๋ฅธ ํšŒ์› ์ •๋ณด ์กฐํšŒ" ๋กœ์ง์—์„œ ๋ฐœ์ƒํ•˜๋˜ ์ค‘๋ณต ์ œ๊ฑฐ.
  3. ํ™•์žฅ์„ฑ ๋ฐ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ

    • ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ ์š”๊ตฌ ์‚ฌํ•ญ์€ Facade์—์„œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์„œ๋น„์Šค ๋กœ์ง ์ˆ˜์ •์ด ์ตœ์†Œํ™”๋จ.

๊ฒฐ๋ก 

ํผ์‚ฌ๋“œ ํŒจํ„ด์„ ์ ์šฉํ•˜์—ฌ, ๊ธฐ์กด์˜ ์ค‘๋ณต๋œ ๋กœ์ง์„ ์ œ๊ฑฐํ•˜๊ณ  ์œ ์—ฐํ•œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜ ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.
ํด๋ผ์ด์–ธํŠธ๋Š” ๋‚ด๋ถ€ ๋กœ์ง์— ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ  Facade ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๊ฐ€๋…์„ฑ๊ณผ ํ™•์žฅ์„ฑ ๋ชจ๋‘๋ฅผ ๋†’์ด๋Š” ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.

ChatGPT์˜ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ธก๋ฉด๋ถ„์„

Facade์˜ ์—ญํ•  ๋ช…ํ™•ํ™”:
ํ˜„์žฌ UserInfoFacade๊ฐ€ ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜๊ณ  ์บ์‹œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Facade ํŒจํ„ด์˜ ๋ชฉ์ ์€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์„œ๋ธŒ ์‹œ์Šคํ…œ์˜ ๋ณต์žก์„ฑ์„ ์ˆจ๊ธฐ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ, ์ถ”๊ฐ€์ ์ธ ์„œ๋ธŒ ์‹œ์Šคํ…œ์ด๋‚˜ ๋ณต์žกํ•œ ๋กœ์ง์ด ๋” ์žˆ๋‹ค๋ฉด Facade๊ฐ€ ์ด๋ฅผ ๋” ์ž˜ ๊ฐ์‹ธ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ์ธ์ฆ, ๊ถŒํ•œ ๊ฒ€์‚ฌ, ๋กœ๊น… ๋“ฑ ๋‹ค๋ฅธ ์„œ๋ธŒ ์‹œ์Šคํ…œ๊ณผ์˜ ์—ฐ๊ณ„๊ฐ€ ์žˆ๋‹ค๋ฉด Facade์—์„œ ์ด๋ฅผ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

DTO ๋ณ€ํ™˜ ๋กœ์ง์˜ ์œ„์น˜:

ํ˜„์žฌ DTO ๋ณ€ํ™˜ ๋กœ์ง์ด Facade์™€ ์ปจํŠธ๋กค๋Ÿฌ ์–‘์ชฝ์— ๋ถ„์‚ฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€ํ™˜ ๋กœ์ง์„ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Facade ๋‚ด์—์„œ ๋ชจ๋“  DTO ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ปจํŠธ๋กค๋Ÿฌ๋Š” Facade์—์„œ ๋ฐ˜ํ™˜๋œ DTO๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ†ต์ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์บ์‹œ ๊ด€๋ฆฌ์˜ ์ถ”์ƒํ™”:

์บ์‹œ ๋กœ์ง์ด Facade์— ์ง์ ‘ ํฌํ•จ๋˜์–ด ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ๋ณ„๋„์˜ ์บ์‹œ ๊ด€๋ฆฌ ์„œ๋น„์Šค๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด Facade์˜ ์ฑ…์ž„์„ ๋”์šฑ ๋ช…ํ™•ํžˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, UserInfoCacheService๋ฅผ ๋งŒ๋“ค์–ด ์บ์‹œ ๊ด€๋ จ ๋กœ์ง์„ ์ „๋‹ดํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

profile

0๊ฐœ์˜ ๋Œ“๊ธ€