티스토리 뷰

3. 정적 팩토리 메서드

:: 객체를 생성할 수 있는 방법을 단 하나의 정적 메서드 방식으로만 가능하게 제한

  • 팩토리 메서드(Factory Method Pattern)
    :: 캡슐화된 Factory 클래스가 대리하여 객체 생성 및 반
    :: 클라이언트에서 new 키워드를 통한 생성 X
  • 정적 메서드의 의의 => 기존 객체에서 새로운 객체로의 변환
// 생성자를 Lombok 어노테이션으로 private 설정 가능
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
// 적용
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Member {
    private Integer id;
    private String name;
    private int age;
    private String email;

    public static Member from(MemberCreateRequestDto requestDto) {
        return new Member(
                null,
                requestDto.getName(),
                0,
                requestDto.getEmail()
        );
    }
}
MemberCreateRequestDto requestDto = new MemberCreateRequestDto("Baron", "baron@example.com");
// 생성자가 Private 가 되었으므로 외부에서 호출이 불가 -> 메서드로 대체
Member baron = Member.from(requestDto);

3.1 정적 메서드를 통한 객체 생성의 장점

1) 메서드가 이름을 가질 수 있음 -> 시멘틱이 명확

2) 호출마다 새 객체를 생성할 필요가 없어짐 (-> 생성 객체 수 제한)

3) 하위 자료형 객체를 반환 가능 -> 상속 사용 시의 이점, but 보통은 조합을 사용하기에 체감은 낮음

4) 객체 생성의 캡슐화 가능 -> 생성자도 가능...


3.2 싱글톤 패턴(Singleton Pattern)

:: 하나의 클래스에 대해 단 하나의 인스턴스만 생성되도록 보장

:: 해당 인스턴스에 전역적으로 접근할 수 있게 하는 패턴

 

  • 구현
더보기
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Member {
    private static Member instance; // 하나의 인스턴스만을 공유하도록 static 사용
    protected Integer id;
    protected String name;
    protected int age;
    protected String email;

    public static Member getInstance() { // 외부에서 사용하는 메서드
        if (Objects.isNull(instance)) {
            instance = new Member();
        }
        return instance;
    }
}

- 단점 :: 멀티 스레드 환경에서 if문에 동시 접근 시, 예상치 못한 오류가 발생할 가능성 존재


- 해결 1

:: 함수 단위 Bloacking으로 동시성 문제 해결

:: synchronized

  • 구현
더보기
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Member {
    private static Member instance;
    protected Integer id;
    protected String name;
    protected int age;
    protected String email;

    public synchronized static Member getInstance() { // sysnchronized를 통해 동시 접근 방어
        if (Objects.isNull(instance)) {
            instance = new Member();
        }
        return instance;
    }
}

- 단점 :: syschronized는 동기적으로 작동하므로 성능저하를 불러옴


- 해결 2

:: 변수 생성 단위 Blacking으로 동시성 문제 해결

:: volatile + synchronized

:: volatile을 통해 JVM은 해당 변수를 복사가 아닌 주메모리에서 확인하고 사용-> 가시성 보장 

  • 구현
더보기
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Member {
    private volatile static Member instance; // volatile키워드
    protected Integer id;
    protected String name;
    protected int age;
    protected String email;

    public static Member getInstance() {
        synchronized (Member.class) { // 멀티 스레드에서 동시 접근 방어
            if (Objects.isNull(instance)) {
                instance = new Member();
            }
        }
        return instance;
    }
    
}

- 단점 :: 주메모리에 접근에 따른 비용 증가 및 여전히 동기적으로 작동하므로 성능저하를 불러옴


- 해결 3

:: Bill Pugh Singleton Design

:: 정적 내부 클래스 로딩 시, 인스턴스를 초기화(지연 초기화)

:: getInstance()를 통해서만 인스턴스 반환 및 관리

  • 구현
더보기
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Member {
    private static class LazyHolder {
        private static final Member UNIQUE_INSTANCE = new Member();
    }

    protected Integer id;
    protected String name;
    protected int age;
    protected String email;

    public static Member getInstance() {
        return LazyHolder.UNIQUE_INSTANCE;
    }
}

 


참고

ASAC 수업자료

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함