< effective java 3편과 백기선님의 youtube 강의를 토대로 쓴 글입니다. >

지난 시간에 했던 내용

  • 점층적 생성자 패턴 : 매개변수가 0~N개까지 모두 선언해서 사용하는 것

  • 자바빈즈 패턴 : 매개변수 없는 생성자로 객체 만들고, setter를 사용하는 것

  • 빌더 패턴 : 클라이언트 코드에서 필요한 객체를 직접 생성하는 대신, 그 전에 필수 인자들을 전달하여 빌더 객체를 만든 뒤, 빌더 객체에 정의된 설정 메서드들을 호출하여 인스턴스를 생성하는 것



오늘의 주제 - 생성자 대신 정적 팩터리 메서드를 고려하라.   (static factory method)



정적 팩터리 메서드란 무엇인지 코드를 보면서 알아보자.

<코드 1.>

public class Person {

   private String name;

   private int age;

 

   public String getName() { return name; }

   public void setName(String name) { this.name = name; }

 

   public int getAge() { return age; }

   public void setAge(int age) { this.age = age; }

 

   private Person(){ }

   public static Person newPerson(){

       return new Person();

   }

 

   public static void main(String[] args) {

       Person conatuseus=Person.newPerson();

   }

}

위와 같이 생성자가 있고, public static인 newPerson 메서드가 있다.

newPerson 메서드는 Person 객체를 생성해서 반환한다.

main에서 Person 객체를 “Person.newPerson()” 이렇게 생성할 수 있다.

이렇게 정적 팩터리 메서드는 public static 팩토리 메서드를 사용해서 해당 클래스의 인스턴스를 만드는 방법이다.

쉽게 말해서 객체를 생성하는 메서드를 만들고, static으로 선언하는 기법이다.



장점

1. 이름을 가질 수 있다.

생성자에 넘기는 매개변수와 생성자 자체만으로는 반환될 객체의 특성을 제대로 설명하지 못한다.

 

반면 정적 팩터리는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다.

<코드 1>에서 Person클래스에 다음과 같은 메서드를 추가했다고 생각해보자.

 

public static Person withName(String name){

       Person p=new Person();

       p.setName(name);

       return p;

   }

 

이 메서드를 사용하면 main에 Person 객체를 생성할 때 다음과 같이 생성할 수 있다.

 

Person firstPerson=Person.withName(“conatuseus”);

 

객체를 생성하는 위의 코드만 보더라도 이름이 conatuseus인 Person이라는 것을 알 수 있다. 따라서 사용하기 쉽고, 읽기 편하다.

 

또, 생성자는 시그니처에 제약이 있다.

똑같은 타입을 파라미터로 받는 생성자를 두 개 만들 수 없다. 이런 경우에도 public static 팩토리 메서드를 사용하는 것 유용하다.

 

public Person(String name){

         this.name=name;

}

public Person(String address){

         this.address=address;

}

위와 같이 똑같은 타입을 파라미터로 받는 생성자 같이 만들 수 없다.

따라서 이것을 public static 팩토리 메서드로 만들어보면 다음과 같다.

 

public Person withName(String name){

         Person p=new Person();

         p.setName(name);

         return p;

}

 public Person withAddress(String address){

         Person p=new Person();

         p.setAddress(address);

         return p;

}



2. 반드시 새로운 객체를 만들 필요가 없다.

불변(immutable) 클래스인 경우나 매번 새로운 객체를 만들 필요가 없는 경우에 미리 만들어둔 인스턴스 또는 캐시해둔 인스턴스를 반환할 수 있다.

 

방법은 다음과 같다.

 

   public static final Person person=new Person();

   public static Person getPerson(){

       return person;

   }

 

public static final로 person 인스턴스를 생성해놓고 public static 메서드인 getPerson으로 가져다가 쓰는 것이다.




3. 반환 타입의 하위 타입 인스턴스를 만들 수 있다.

 

public class Person {

   private String name;

   private int age;

   private String address;

 

   private Person(){}

 

   static class Student extends Person{

   }

   static class Teacher extends Person{

   }

 

   public static Person getStudent(){

       return new Student();

   }

   public static Person getTeacher(){

       return new Teacher();

   }

   

   public static void main(String[] args) {

       Person conatuseus=Person.getStudent();

       Person dynamiseus=Person.getTeacher();

   }

}

이 코드에서 Student, Teacher 클래스는 Person의 하위 타입이다.

main에서 conatuseus는 Student 타입 인스턴스이고, dynamiseus는 Teacher 타입 인스턴스이다.

이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 ‘엄청난 유연성’을 가진다.




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

 3번 장점과 같은 이유로 객체의 타입이 다를 수 있다. 매개변수에 따라 선택적인 Sub class 객체를 반환할 수 있다.

이 예는 Enum을 자세히 공부하고 다시 적어보자.




단점.

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

'Java' 카테고리의 다른 글

점층적 생성자 패턴, 자바빈즈 패턴, 빌더 패턴  (0) 2019.03.13
Annotation (어노테이션)  (0) 2018.11.13

+ Recent posts