9osari.log
← 목록으로

[DDD] Factory Method & Repository

Factory method

“객체를 어떻게 만드는지” 보다 “왜/언제 만들어 지는지” 를 드러내고 복잡한 생성과정을 감추는 역할

Factory method의 장점

Repository 사용

User.java (엔티티)

public static User register(String username, String email, String encryptedPassword, String nickname, String phone) {
        return new User(
            username,
            email,
            encryptedPassword,
            nickname,
            phone
        );
    }

Service 계층

@Override
public void registerUser(UserRegistrationRequest request) {
    userValidator.RegisterValidate(request.username(), request.email());

    String encoded = passwordEncoder.encode(request.password());

    User user = User.register(request.username(), request.email(), encoded, request.nickname(), request.phone());

    userRepository.save(user);
}

new를 사용했을 경우

@Override
public void registerUser(UserRegisterRequest request) {
    //잘못된 사용 가능성: 암호화를 빼먹을 수 있음
    //왜? 생성하는지 보는사람이 모를 수 있음
    User user = new User(
        request.username(),
        request.email(),
        request.getPassword(), // 평문 들어감 (보안 문제)
        request.nickname(),
        request.phone()
    );

    userRepository.save(user);
}

생성자는 객체 내부 구현 세부사항을 드러내는 반면, 팩토리 메서드는 도메인 언어로 행위를 드러내어 모델을 더 읽기 쉽게 만든다.


Repository

도메인 객체를 컬렉션처럼 다루게 해주고, DB 세부사항은 감추게 해준다.

Repository의 장점

규격서 개정 DAO → Repository 리팩터링

기존 개정 로직

@Override
public SpcfShtMVo rvsnSpcfsht(SpcfShtMVo vo) {
    // 원본 규격서 / 규격서 최종 규격서 여부 N 처리
    updateOriginalSpcfSht(vo);
  
    /*********************저장 METHOD***********************/
    if(!this.spcfShtValidCheck(vo)){
      throw new CustomException("해당 공정으로 등록된 품목 규격서가 존재합니다.");
    }
  
    // 개정 규격서 등록 SELECT INSERT , 개정 규격서 일련 번호 반환
    SpcfShtMVo rvsnSpcfshtVo = createNewSpcfSht(vo);
    vo.setRvsnSpcfshtSn(rvsnSpcfshtVo.getSpcfshtSn()); // 개정 규격서 일련번호
    vo.setOriginSpcfshtSn(rvsnSpcfshtVo.getOriginSpcfshtSn()); // 기존 규격서 일련번호
  
    // 개정 규격서 / 품목채취정보 SELECT INSERT
    createNewItemColctInfo(vo);
  
    // 개정 규격서 / 품목별 규격서 이력 저장
    saveReversionSpcfshtHstry(vo);
  
    // 개정 규격서 / 품목채취정보 SELECT INSERT
    spcfShtMDao.insertNewItemColctInfo(vo);
  
    // 개정 규격서 / 품목모니터링Point SELECT INSERT
    createNewItemMonitrgPoint(vo);
  
    // 개정 규격서 / 규격서-시험항목 및 변수 SELECT INSERT
    createNewTestArtcls(vo);
  
    // 개정된 규격서 조회
    return spcfShtMDao.selectSpcfsht(vo);
}

도메인 엔티티

@Entity
@Table(name = "SY_ITEM_MONITRG_POINT")
public class SpcfShtMVo {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
		...
    private String wkroomAtPointSn;
    private String spcfshtSn;
    private String bplcCd;
    
    private boolean last; // 최종 규격 여부
    public SpcfShtMVo revise() {
        this.last = false;
        return new SpcfShtMVo(/* 필요한 값 복사/초기화 */);
    }
}

레파지토리 인터페이스

@Repository
public interface SpecificationSheetRepository extends JpaRepository<SpcfShtMVo, Long> {
    Optional<SpcfShtMVo> findById(Long id);
    
    //커스텀 쿼리도 정의 가능
}

서비스 레이어

@Transactional
public SpcfShtMVo reviseSpecification(Long sheetId) {
    SpcfShtMVo original = repository.findById(sheetId)
        .orElseThrow(() -> new NotFoundException("규격서 없음"));

    SpcfShtMVo revised = original.revise();

    repository.save(original);
    repository.save(revised);

    return revised;
}

DAO는 데이터 접근 세부사항을 드러내는 반면, 리포지토리는 도메인 언어로 의도를 드러내어 모델을 더 순수하게 만든다.



「도메인 주도 설계란 무엇인가? 쉽고 간략하게 이해하는 DDD」를 읽고
···
← PREV [JAVA] 순회와 정렬 NEXT → [DDD] 도메인 주도 설계란 무엇인가