본문 바로가기

개발

디자인 패턴을 적용해보자 - 팩토리(4). (pizza 예제 아님)

1. 팩토리 메서드 패턴 돌아보기


팩토리 메서드 패턴을 이용하여 리펙토링 했지만 찜찜함이 있었다. 간단한 팩토리에서 했던 분기 작업을 Controller 단으로 미룬 게 아닌가? 하는 생각 때문이었다. 

헤드 퍼스트 디자인 패턴에서 예시로 들었던것도 팩토리 매서드 패턴을 적용한 타이밍은 팩토리의 종류(피자 매장의 타입) 자체가 달라지는 경우였다. 뉴욕 스타일의 피자 매장에서는 뉴욕스타일만 만들 것이고 클라이언트는 계속 그 요청만 하니 팩토리 자체를 추상화한 것이었다.

그래서 지금 내가 프로젝트의 상황에서는 팩토리 메서드 패턴 적용까지는 갈 필요가 없고 간단한 팩토리에서 타입에 따라 분리하는게 더 맞아 보인다. 지금 상황에서 새로운 댓글 타입이 추가된다면 TypesRository를 상속하는 클래스 한 개, CommentSerivce를 상속하는 클래스 한 개로 총 2개를 추가해야 하지만 간단한 팩토리를 이용하면 TypesRository 상속 클래스 하나만 추가하면 되니까.

 

 

 

 

 

 

2. 향상된 Simple Factory


향상된 간단한 팩토리 태그로 이동하여 코드를 확인해 보자.

https://github.com/SongHae8640/designPatternApply

 

GitHub - SongHae8640/designPatternApply

Contribute to SongHae8640/designPatternApply development by creating an account on GitHub.

github.com

git checkout tags/factory_simpleImprove

 

 

 

TypesRepository 가 타입을 갖게 하기 위해 추상 클래스로 변경하고 이를 상속하도록 변경한다.

public abstract class TypesRepository {
    CommentType commentType;
    abstract void checkTypesId(Long typesId);
    abstract void addCommentCount(Long typesId);
    CommentType getCommentType() {
        return commentType;
    }
}

@Component
public class TypesDrinkRepository extends TypesRepository {
    private final DrinkRepository drinkRepository;

    public TypesDrinkRepository(DrinkRepository drinkRepository) {
        this.drinkRepository = drinkRepository;
        this.commentType = CommentType.DRINK;
    }

    @Override
    public void checkTypesId(Long typesId) {
        drinkRepository.findById(typesId)
                .orElseThrow(() -> new NoSuchElementException("존재하지 않는 음료입니다."));
    }

    @Override
    public void addCommentCount(Long typesId) {
        drinkRepository.findById(typesId)
                .orElseThrow(() -> new NoSuchElementException("존재하지 않는 음료입니다."))
                .addCommentCount();
    }
}


@Component
public class TypesBoardRepository extends TypesRepository {

    private final BoardRepository boardRepository;

    public TypesBoardRepository(BoardRepository boardRepository) {
        this.boardRepository = boardRepository;
        this.commentType = CommentType.BOARD;
    }

    @Override
    public void checkTypesId(Long typesId) {
        boardRepository.findById(typesId)
                .orElseThrow(() -> new NoSuchElementException("존재하지 않는 게시글입니다."));
    }

    @Override
    public void addCommentCount(Long typesId) {
        boardRepository.findById(typesId)
                .orElseThrow(() -> new NoSuchElementException("존재하지 않는 게시글입니다."))
                .addCommentCount();
    }
}

 

 

 

 

팩토리 메서드 패턴의 클라이언트(Controller)에서는 댓글 타입을 map 의 key로 저장했던 방식을 SimpleFactory(RepositoryFactory)에 적용한다.

@Component
public class RepositoryFactory {

    private final Map<CommentType, TypesRepository> repositoryMap;

    public RepositoryFactory(List<TypesRepository> typesRepositoryList) {
        this.repositoryMap = typesRepositoryList.stream()
                .collect(java.util.stream.Collectors.toMap(TypesRepository::getCommentType, typesRepository -> typesRepository));
    }

    public TypesRepository getRepository(CommentType commentType) {
        return repositoryMap.get(commentType);
    }
}

 

 

 

3. 테스트


코드는 수정되었지만 테스트 코드 작성을 미리 해둔 덕분에 정상적으로 조회 및 저장된다는 것을 확인할 수 있다.

 

 

 

 

 

 

 

4. 후기


이렇게 팩토리를 적용해보면서 책으로만 읽었을 때랑은 다르게 더 깊은 고민을 해볼 수 있었다. 이후 다른 디자인 패턴도 내 프로젝트에서 적용해 보면서 디자인 패턴의 맛을 음미해 봐야겠다.