관리 메뉴

bright jazz music

[effective java 3rd - ch.02 객체의 생성과 파괴] Item01 : 생성자 대신 정적 팩터리 메서드를 고려하라 본문

JAVA/effective java 3rd edition

[effective java 3rd - ch.02 객체의 생성과 파괴] Item01 : 생성자 대신 정적 팩터리 메서드를 고려하라

bright jazz music 2022. 9. 5. 09:20

- 클라이언트가 클래스의 인스턴스를 얻는 전통적인 수단은 public 생성자(constructor)를 사용하는 것이다.

- 그러나 클래스는 생성자와 별도로 정적 팩토리 메서드(static factory method)를 제공한다.

- static factory method는 해당 클래스의 인스턴스를 반환한다.

 

예시)

public static Boolean valueOf(boolean b) {
	return b ? Booelan.TRUE : Boolean.FALSE
}

// boolean 기본 타입의 Boxed Class인 Boolean에서 발췌한 것.
// 이 메서드는 기본 타입인 boolean 값을 받아 Boolean 객체 잠조로 변환해 준다.

 

 

클래스는 클라이언트에게 public  생성자 대신 (혹은 생성자와 더해) 정적 팩터리 메서드를 제공할 수 있다.

 

 

 

정적 팩터리 메서드 제공의 장단점

 

장점.

 

1. 이름을 가질 수 있다.

 

- 이름을 가짐으로써 반환될 객체의 특성을 보다 쉽게 유추할 수 있다.

- 하나의 시그니처로는 하나의 생성자만 만들 수 있고, parameter의 순서를 서로 다르게 한 생성자를 추가한 방식으로 이를 피할 수 있다. 그러나 이 경우 각 생성자가 어떤 역할을 하는지 명확히 기억하기 어렵기 때문에 개발자가 호출 실수를 할 수 있다. 최악의 경우 클래스 설명문서를 찾아보지 않으면 사용하기 어려울 수도 있다.

- 정적 팩터리 메서드는 이름(메서드 이름)을 가질 수 있기 때문에 이런 제약이 없다. 한 클래스에 시그니처가 같은 생성자가 여러 개 필요한 경우, 생성자를 정적 팩터리 메서드로 바꾸고 각각의 차이를 잘 드러내는 메서드 명을 지어주자.

 

2. 호출 될 때마다 인스턴스를 새로 생성하지 않아도 된다.

 

- 정적 팩터리 메서드가 존재하면 불변 클래스(immutable class)가 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 방식으로 불필요한 객체 생성을 피할 수 있다. 예를 들어 Boolean.valueOf(boolean) 메서드는 객체를 아예 생성하지 않는다. 특히 생성 비용이 큰 객체가 자주 호출되는 상황이라면 이 방법을 사용해서 성능을 높일 수 있다. 플라이웨이트 패턴(flyweight pattern)과 맥락이 유사하다.

- 반복되는 요청에 같은 객체를 반환하는 식으로 정적 팩터리 방식의 클래스는 언제 어느 인스턴스를 살아 있게 할지를 철저히 통제할 수 있다. 이런 클래스를 instance-controlled 클래스라고 한다.

 

인스턴스를 통제하는 이유는 클래스를 싱글턴으로 만들 수도, 인스턴스 불가(noninstantiable)로 만들 수도 있기 때문이다. 또한 불변값 클래스에서 동치인 인스턴스가 단 하나뿐임을 보장할 수 있다.(a==b일 때만 a.equals(b)가 성립) 인스턴스 통제는 플라이웨이트 패턴의 근간이 되며 열거타입은 인스턴스가 하나만 만들어짐을 보장한다.

 

3. 정적 팩터리 메서드는 반환 타입의 하위 객체를 반환할 수 있는 능력이 있다.

 

- 이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 유연성을 개발자에게 부여한다. API를 만들 때 이 유연성을 응용하면 구현 클래스를 공개하지 않고도 그 객체를 반환할 수 있어 API를 작게 유지할 수 있다. 이는 인터페이스를 정적 팩터리 메서드의 반환 타입으로 사용하는 인터페이스 기반 프레임워크를 만드는 핵심 기술이기도 하다.

 

4.  입력 매개변수(파라미터)에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

 

- 반환 타입의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하든 상관없다. 심지어 다음 릴리스에서는 또 다른 클래스의 객체를 반환해도 된다. 예를 들어 EnumSet 클래스는 public 생성자 없이 오직 정적 팩터리만 제공하는데 OpenJDK에서는 원소의 수에 따라 두 가지 하위 클래스 중 하나의 인스턴스를 반환한다.  원소가 64개 이하면 원소들을 long 변수 하나로 관리하는 RegularEnumSet의 인스턴스를, 65개 이상이면 long  배열로 관리하는 JumboEnumSet의 인스턴스를 반환한다.

- 클라이언트는 이 두 클래스의 존재를 모른다. 원소가 적을 때 RegularEnumSet을 사용할 이점이 없어진다면 다음 릴리스 때는 이를 삭제해도 문제 없고, 같은 맥락에서 추가해도 문제가 없다. 클라이언트는 팩터리가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수도 없고 알 필요도 없다. EnumSet의 하위 클래스이기만 하면 되는 것이다.

 

5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

 

- 이 대표적인 예가 JDBC이다. 서비스 제공자 프레임 워크에서 provider는 서비스의 구현체다. 이 구현체들을 클라이언트에 제공하는 역할을 프레임워크가 통제하며 클라이언트를 구현체로부터 분리한다.

 

- 서비스 제공자 프레임워크는 3개의 핵심 컴포넌트로 이루어진다. 그것은 다음과 같다. 구현체의 동작을 정의하는 서비스 인터페이스(Service interface), 제공자가 구현체를 등록할 때 사용하는 제공자 등록 API(provider registration API), 클라이언트가 서비스의 인스턴스를 얻을 때 사용하는 서비스 접근 API(service access API)이다.

 

- 클라이언트는 서비스 접근 API를 사용할 때 원하는 구현체의 조건을 명시할 수 있다. 조건을 명시하지 않으면 기본 구현체를 반환하거나 지원하는 구현체들을 하나씩 돌아가며 반환한다. 이 서비스 접근 API가 바로 서비스 제공자 프레임워크의 근간인 '유연한 정적 팩터리'이다.

 

- 위 3개의 컴포넌트와 더불어 종종 사용되는 서비스 인터페이스(service provider interface)라는 네 번째 컴포넌트가 사용된다. 이 컴포넌트는 서비스 인터페이스와 인스턴스를 생성하는 팩터리 객체를 설명한다. 서비스 제공자 인터페이스가 없다면 각 구현체를 인스턴스로 만들 때 리플렉션을 사용해야 한다.

 

- JDBC에서는 Connection이 서비스 인터페이스 역할을 DriverManager.registrationDriver가 제공자 등록 API 역할을, Driver가 서비스 제공자 인터페이스 역항를 수행한다.

 

서비스 제공자 프레임워크 패턴에는 변형이 있다. 예를 들어 서비스 접근 API는 공급자가 제공하는 것보다 더 풍부한 서비스 인터페이스를 클라이언트에 반환할 수 있다. Bridge pattern이라 알려진 것이다. 의존성 주입(의존 객체 주입) 프레임워크도 강력한 서비스 제공자라고 생각할 수 있다.

 

 

 

 

 

 

단점.

 

 

1. 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 필요하면 하위클래스를 만들 수 없다.

- 앞서 이야기한 컬렉션 프레임워크의 유틸리티 구현 클래스들은 상속할 수 없다. 이 제약은 상속보다 컴포지션을 사용하도록 유도하고 불변타입(immutable type)으로 만들려면 이 제약을 지켜야 한다는 점에서 오히려 장점으로 받아들일 수 있다.

 

2. 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.

- 생성자처럼 API 설명에 명확히 드러나지 않으니 사용자는 정적 팩터리 메서드 방식 클래스를 인스턴화할 방법을 알아내야 한다.

 

 

 

 

핵심

- 정적 팩터리 메서드와 public 생성자는 각자의 쓰임새가 있으니 상대적인 장단점을 이해하고 사용하는 것이 좋다.

- 하지만 정적 팩터리를 사용하는 게 유리한 경우가 더 많다. 따라서 무작정 public 생성자를 제공하던 습관이 있다면 개선하라.

 

---

 

아래는 Baeldung의 포스팅이다. 위의 설명만으로는 잘 이해되지 않아 baeldung의 포스팅을 번역해 보았다.

 

https://www.baeldung.com/java-constructors-vs-static-factory-methods

 

java Constrouctors vs. static Factory methods

 

1.Overview

생성자는 완전히 초기화 된 클래스의 인스턴스를 얻기 위한 기본적인 메커니즘이다. 결과적으로 그것들은 의존성을 주입하기 위해 요구되는 모든 인프라스트럭쳐를 제공한다. 그것이 수동적인 방식이든 자동적인 방식이든 말이다.

 

그럼에도 불구하고 몇 가지 특정 사용 사례에서는 동일한 결과를 얻기 위해 정적 팩토리 메서드에 의존하는 것이 좋다. (나는 다음과 같이 번역했다. "그렇다고 하더라도, 몇 가지의 구체적인  사례에서, 그것은 정적 팩토리 메소드를 사용하는 것이 동일한 결과를 달성하는 데 선호된다."라고 번역했는데 이는 it ~ to를 그대로 번역해버렸기 때문이다.)

 

이 튜토리얼에서, 우리는 정적 팩토리 메서드와. plain old java 생성자를 사용할 때의 대한 장단점을 강조한다. 

 

2. 생성자에 비해 정적 팩터리 메서드를 사용하는 것에 대한 장점

자바와 같은 객체지향 언어에서 생성자를 사용하는 것에 어떤 문제가 있을까? 전반적으로, 없다. 그럼에도 불구하고 Joshua Block의 Effective Java의 아이템 1은 분명히 명시한다;

"생성자 대신 정적 팩터리 메서드를 고려하라"

 

생성자 대신 정적 팩터리 메서드를 사용하는 것이 특효약은 아니지만, 이러한 접근 방식을 유지해야 하는 가장 강력한 이유들이 존재한다.

 

1. 생성자는 의미 있는 이름을 가지지 않는다. 그래서 생성자들은 언제나 언어에 의해 부여된 관습적인 표준 명명 방식에 제한된다 (나의 추가 설명: 즉, 특정 언어에서 생성자를 사용하여 객체를 생성하는 방식에 얽매일 수밖에 없다는 것이다. 자바에서 생성자를 사용해 인스턴스를 얻어내는 방식을 생각해 보자). 정적 팩토리 메서드는 의미 있는 이름을 가질 수 있으므로 수행하는 작업을 명시적으로 전달한다.

(다음은 내 번역이다. "그러나 정적 팩토리 메소드는 의미 있는 이름을 가질 수 있고 더불어 그들이 하는 일까지 노골적으로 전달한다.")

 

2. 정적 팩토리 메서드는 메서드, 서브타입, 원시 타입을 구현하는 동일한 타입을 반환할 수 있다. 따라서 보다 유연한 반환 유형을 제공한다.

(나는 range를 반드시 넣어서 번역하느라 고민했는데 구글 번역은 아예 빼버렸다. 번역이 훨씬 매끄러워졌다.)

 

3. 정적 팩터리 메서드는 완전히 초기화된 인스턴스를 사전에 구성하는 데 필요한 모든 로직을 캡슐화 할 수 있다. 따라서 정적 팩터리 메서드는 이 추가적인 로직을 생성자의 외부로 옮기는 데 사용될 수 있다. 이러한 정적 팩토리 메서드의 사용은 생성자가 필드를 초기화 하는 것 이외에 추가 작업을 수행하는 것을 방지한다.

 

4. 정적 팩토리 메서드는 Controlled-instanced 메서드가 될 수 있다. 싱글턴 패턴이 이 기능의 가장 눈에 띄는 예시이다.

(원문: Static factory methods can be controlled-nstanced methods, with the Singleton pattern being the most glaring example of this feature)

 

 

 

3. JDK의 정적 팩토리 메서드

JDK에는 상기한(outlined above) 정적 팩터리 메서드의 장점을 대표적으로 보여주는 수 많은 예시들이 있다. 일부를 살펴보자.

 

3.1. The String Class

잘 알려진 String 인턴으로 인해 String 클래스 생성자를 사용하여 새 String 객체를 생성할 가능성은 거의 없다. 그럼에도 불구하고 이것은 완벽하게 합법적이다.

 

(나는 다음과 같이 번역했다. "우리는 스트링 객체를 얻기 위해 스트링 클래스의 생성자를 사용하지 않을 가능성이 높다." it is very unlikely we'll use the String class..."를 그대로 번역한 것인데 번역기의 번역처럼 가능성이 거의 없다고 번역하는 것이 더욱 매끄러운 것 같다.)

 

String value = new String("Baeldung");

이 경우, 생성자가 새로운 스트링 객체를 생성한다. 이는예상된 행동(번역기: 동작)이다.

만약 스트링 객체를 생성하기 위한 대안으로 정적 팩터리 메서드를 사용하기를 원한다면 아래와 같은 valueOf() 메서드의 구현을 사용할 수 있다.

 

String value1 = String.valueOf(1);	//1
String value2 = String.valueOf(1.0L);	//1.0
String value3 = String.valueOf(true);	//true
String value4 = String.valueOf('a');	//a

 

valueOf() 메서드의 오버로딩(메서드 오버로딩)된 구현이 여러 개이다. 이것들은 해당 메소드에 전달된 아규컨트의 유형에 따라서 각각 새로운 스트링 객체를 반환한다. ( 예를 들면, int, long, boolean, char 등)

(나의 서명: 위의 코드에선느 각각 1(int), 1.0(long), true(boolean), 'a'(char)를 valueOf() 메서드에 아규먼트로서 전달한다. valueOf()메서드는 전달된 아규먼트의 타입에 따라서 새로운 스트링 객체를 생성한다.)

 

정적 메서드의 이름은 그 메서드의 역할을 상당히 명확히 나타낸다. 또한 정적 팩토리 메서드 명명을 위한 자바 생태계의 잘 정립된 표준을 준수한다.(나는 부합한다고 번역했다.)

 

4. Custom Static Factory Method

물론 우리가 자체적으로(번역기: 우리 고유의) 정적 팩토리 메서드를 구현할 수도 있다. 어떤 경우에(언제) 그것이 정말로 가치 있을까? 일반적인 생성자에 의한 클래스 인스턴스 생성 대신 말이다.

 

간단한 예시를 살펴보자.

 

이 평범한(번역기: 순진한) User 클래스를 생각해 보자.

public class User {
    
    private final String name;
    private final String email;
    private final String country;
    
    public User(String name, String email, String country) {
        this.name = name;
        this.email = email;
        this.country = country;
    }
    
    // standard getters / toString
}

 

이 경우, 표준적인 생성자보다 정적 팩토리 메서드가 나을 수 있다는 것을 알려주는 가시적인 경고가 없다.

 

만약 모든 User 인스턴스의 country 필드에 기본값을 넣으려면 어떻게 해야 할까?(나: 어떻게 할까)

 

필드를 기본값으로 초기화하면 생성자도 리팩터링해야 하므로 디자인이 더 딱딱(rigid)해진다.

(나: "만약 필드가 기본값을 갖도록 초기화 한다면, 우리는 생성자 역시 리팩터를 해야할 뿐만 아니라, 디자인을 더욱 견고하게 만들어야 할 것이다." 완전히 틀린 번역을 하였다.)

 

생성자를 사용하는 방식 말고 정적 팩토리 메서드를 사용할 수 있다.

 

public class User {
    
    private final String name;
    private final String email;
    private final String country;
    
    public User(String name, String email, String country) {
        this.name = name;
        this.email = email;
        this.country = country;
    }
    
    //정적 팩토리 메서드
    public static User createWithDefaultCountry(String name, String email) {
    	return new User(name, email, "Argentina");
    }
    
    // standard getters / toString
}

 

이렇게 country 필드에 기본값이 배정된 User 인스턴스를  얻을 수 있다.

User user = User.createWithDefaultCountry("John", "john@domain.com");

https://pythontutor.com/

여기서 직접 코드를 작성하여 테스트 해 보았다. 정적 팩터리 메서드는 생성자를 사용해  User인스턴스를 만든다. 그리고 거기에 넘어온 아규먼트들을 넣어 초기화 한다. 이 작업이 완료되면 메소드를 호출한 곳으로 해당 클래스의 인스턴스가 반환된다.

 

//클래스 선언부 public 접근 제한자는 여기에 쓸 수 없다.
class User {
  private final String name;
  private final String email;
  private final String country;
  

  //constructor
  public User(String name, String email, String country) {
       this.name = name;
       this.email = email;
       this.country = country;
  }
  
  //만약 생성자에 파라미터를 지정하지 않고 기본 생성자로 둔다면 아래와 같은 에러가 발생한다
  // 따라서 파라미터가 지정된 생성자를 만들어 줘야 한다.
  
  //Error: constructor User in class User cannot be applied to given types;
  //required: no arguments
  //found: java.lang.String,java.lang.String,java.lang.String
  //reason: actual and formal argument lists differ in length
  
  
  
  
  //static factory method
  public static User createWithDefaultCountry(String name, String email) {
    return new User(name, email, "Argentina")  ;
  }
  
  
  //getter methods. there are no setter methods because fields are final.
  public String getName(){
    return name;
  }
  
  public String getEmail(){
    return email;
  }
  
  public String getCountry(){
    return country;  
  }
  
}



public class YourClassNameHere {

	//main method
    public static void main(String[] args) {
    
      // 호출부
      User sampleUser = User.createWithDefaultCountry("John", "John@domain.com");
      System.out.println(sampleUser);
      System.out.println(sampleUser.getName());
      System.out.println(sampleUser.getEmail());
      System.out.println(sampleUser.getCountry());

    }
}



//User@156643d4
//John
//John@domain.com
//Argentina

 

 

 

 

 

 

5. 추가 로직을 생성자에서 분리하기 (원: Moving Logic out of Constructors)

생성자에 추가 논리를 추가해야 하는 기능을 구현하기로 결정하면 User 클래스가 결함이 있는 디자인으로 빠르게 썩을 수 있다(이 시간까지는 알람 벨이 울려야 함).

(나 : 우리의 User 클래스는 신속히 결함 있는 디자인으로 썩어버릴 수 있다. 만약 우리가 생성자에 추가 로직을 요구하는 기능을 구현한다고 결정한다면 말이다. (알람벨이 이 시간까지 울려야 한다 alarm bells should be sounding off by this time 이 표현을 이해하지 못했다.))

 

User 객체가 생성될 때마다 로그를 남기는 기능을 가진 클래스를 제공하고 싶다고 가정하자.

 

만약 우리가 이 로직을 생성자에 추가한다면, 우리는 단일책임원칙(SRP, Single Responsibility Principle)를 어기게 될 것이다. 우리는 결국 필드를 초기화 하는 것 외에 더 많은 일을 하는 한 덩어리로 뭉쳐진(monolithic ) 생성자를 만들고 말 것이다.

*monolithic: 돌덩이 하나의, 단단히 짜여 하나로 되어 있는. (대체어가 떠오르지 않는다. 나는 '유연하지 못한'이라는 표현밖에는 떠오르지 않았다. 뭉쳐져 있다는 표현을 후에 추가했는데 이상하지는 않은 것 같다.)

 

정적 팩토리 메서드를 사용함으로써 디자인을 깔끔하게 유지할 수 있다.

public class User {
    
    private static final Logger LOGGER = Logger.getLogger(User.class.getName());
    private final String name;
    private final String email;
    private final String country;
    
    // standard constructors / getters
    
    public static User createWithLoggedInstantiationTime(
      String name, String email, String country) {
        LOGGER.log(Level.INFO, "Creating User instance at : {0}", LocalTime.now());
        return new User(name, email, country);
        
        // 정적 팩토리 메서드 내부에 로직과 생성자가 모두 들어 있다.
        // 따라서 생성자 로직을 수정하지 않아도 된다.
    }
}

 

개선된 User 인스턴스를 만드는 방법은 다음과 같다.(원문: Here's how we'd create our improved User instance:)

User user
	= User.createWithLoggedInstantiationTime("John", "john@domain.com", "Argentina");

 

 

(내가 실제로 구동해 보기.)

 

package org.example;

import java.time.LocalTime;
import java.util.logging.Level;
import java.util.logging.Logger;

//클래스 선언부 public 접근 제한자는 여기에 쓸 수 없다.
class User {
    private static final Logger LOGGER = Logger.getLogger(User.class.getName());
    private final String name;
    private final String email;
    private final String country;

    //파라미터를 넣기 위해서는 아래와 같은 생성자가 필요하다.
    public User(String name, String email, String country) {
        this.name = name;
        this.email = email;
        this.country = country;
    }

    // standard constructors / getters

    public static User createWithLoggedInstantiationTime(
            String name, String email, String country) {
        LOGGER.log(Level.INFO, "Creating User instance at ~~~~~~~~~~!!!!!!!!!!!! : {0}", LocalTime.now());
        return new User(name, email, country);

        // 정적 팩토리 메서드 내부에 로직과 생성자가 모두 들어 있다.
        // 따라서 생성자 로직을 수정하지 않아도 된다.
    }

    public String getName() {return this.name;}
    public String getEmail() {return this.email;}
    public String getCountry() {return this.country;}
}


public class YourClassNameHere {

    //main method
    public static void main(String[] args) {

        // 호출부
        User sampleUser 
        	= User.createWithLoggedInstantiationTime("Philip", "Philip@domain.com", "S.Korea");
        System.out.println(sampleUser);
        System.out.println(sampleUser.getName());
        System.out.println(sampleUser.getEmail());
        System.out.println(sampleUser.getCountry());

    }
}


//org.example.User@3b07d329
//Philip
//Philip@domain.com
//S.Korea

//Sep 08, 2022 8:36:49 AM org.example.User createWithLoggedInstantiationTime
//        INFO: Creating User instance at ~~~~~~~~~~!!!!!!!!!!!! : 08:36:49.574

 

 

 

 

 

 

 

 

6. Instance-Controlled Instantiation (인스턴스 제어 인스턴스화)

 

위에서 보여주었듯이, 우리는 완전 초기화 된 객체를 반환하기 전에 로직 덩어리를 캡슐화 해서 정적 팩토리 메서드에 캡슐화 해 넣을 수 있다. 그리고 이 작업은 생성자를 오염시키지 않는다. 생성자가 (초기화 외의) 관련 없는  여러 가지 작업을 수행하는 책임을 맡지 않아도 되기 때문이다.

 

예를 들어, User 클래스를 싱글턴으로 만들고 싶다고 가정해 보자. 우리는 instance-controlled static factory method를 구현함으로써 이 목적을 달성할 수 있다. :

public class User {
    
    private static volatile User instance = null;
    
    // other fields / standard constructors / getters
    
    public static User getSingletonInstance(String name, String email, String country) {
        if (instance == null) {
            synchronized (User.class) {
                if (instance == null) {
                    instance = new User(name, email, country);
                }
            }
        }
        return instance;
    }
}

:volatile은 https://ttl-blog.tistory.com/238 참고

 

 

getSingletonInstance() 메서드의 구현은 Syncronized 블록 때문에 약간의 성능 페널티가 존재하지만 thread-safe하다.

 

이 경우 우리는 지연 초기화(lazy initialization)fmf 사용했다. 이는 인스턴스 제어 정적 팩토리 메서드(instance-controlled static factory method)의 구현을 시연하기 위해서였다.

 

그러나 싱글턴을 구현하는 가장 좋은 방법이  serialization-safe하고 thred-safe한 자바 enum을 사용하는 것이라고 언급할 가치가 있다. 또다른 접근 방식을 사용하여 싱글턴을 구현하는 방법에 대한 세부사항을 확인하려면 다음의 이 글을 참고하라.

 

예상했겠지만, 이 메서드를 통해 User 객체를 얻는 방법은 이전의 예제들과 매우 유사해 보인다.

User user = User.getSingletonInstance("John", "john@domain.com", "Argentina");

 

7. 결론

 

우리는 이 글에서 정적 팩토리 메서드가 일반 생성자를 사용하는 방법보다 나은 사례를 살펴 보았다. 

 

더불어, 이 리팩토링 패턴은 대부분의 IDE가 우리를 위해 수행하는 대부분의 전형적인 워크플로우에 밀접하게 뿌리내리고 있다.

 

물론 Apache NetBeans, IntelliJ IDEA, 그리고 Eclipse는 이와는 미세하게 다른 방법으로 리팩토링을 수행할 것이다. 따라서 IDE 문서를 먼저 체크하라.

 

다른 많은 리팩토링 패턴과 마찬가지로, 우리는 정적 팩토리 메서드를 상당한 주의와 함께 사용해야 한다. 그리고 오직 그것이 유연하고 깔끔한 디자인을 만들수 있는지 여부와, 추가 메서드 구현을 해야하는 비용 사이에 서 절충할 가치가 있는 경우에만 사용되어야 한다.

 

늘 그렇듯이 이 글에서 보인  코드 샘플은 깃허브에서 사용이 가능하다.

 

 

 

 

 

 

 

Comments