본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[Java Design Pattern] 생성자 대신 static factory method를 사용해보자.

by 돼지왕왕돼지 2012. 1. 10.

1. Prerequisite & Reference


[Tutorial] 디자인 패턴이 뭔가요? 왜 필요한가요?




2. Information

 

Static Factory Method 가 뭔가요?


일반적으로 객체를 생성할 때는 생성자 ( Constructor ) 을 이용하죠? 
Object object = new Object(); 와 같이..

Static Factory Method 는 public static method 로서 외부 클래스에서 바로 접근할 수 있는 method 로,
생성자의 역할을 하는 녀석입니다.



Static Factory Method 를 쓰면 뭐가 좋은데요?


1. 생성자와는 달리 자기 나름의 이름을 가질 수 있습니다.


생성자는 Class 이름밖에 못 갖습니다. 예를 들어 Blog 라는 클래스를 만들면 생성자 이름은 무조건 Blog() 여야 하죠.
물론 Parameter 갯수와 종류는 달라 질 수 있지만, 이름 자체는 Blog 여야만 합니다.
이게 무슨 장점이냐고요?
그냥 Blog() 를 호출하는 것보다 반환하는 객체를 더 잘 나타낼 수 있습니다.

예를 들어봅시다. 다음과 같은 constructor 가 있습니다.

public Blog();
public Blog( String powerBloggerID );


둘 다 Blog 라는 이름으로 부르기 때문에 String parameter의 이름인 powerBloggerId 를 알기 전까지는 
저 constructor의 역할을 정확히 알기가 힘듭니다. 
게다가 모두가 다 저 위치에 변수 명을 powerBloggerID 라고 명시할거라 단언할 수도 없죠. 
그렇게 되면 실제 구현 코드를 분석하거나 document 를 참조하는 수고가 더 들게 됩니다.


하지만 이번엔 static factory method 를 이용해봅시다.


public static Blog newBlogInstance();
public static Blog newPowerBlogInstance( String powerBloggerID );


둘 다 Blog 를 return 받지만, 가독성이 훨씬 늘어났습니다. 어떤 성질의 녀석을 return 하는지 한번에 알 수 있죠?
이름이 길어지겠지만, powerBloggerID 라는 변수명을 보장할 수 없는 경우를 고려한다면 두번째 static factory method의
이름은 newPowerBlogInstanceWithBloggerID( String powerBloggerID ); 요런 형태도 괜찮을 것 같습니다.


2. 중복 Signature Constructor의 형태가 가능합니다.

 
 Constructor 가 중복 signature 를 가지지 못한다는 것은 이미 알고 계시죠?

[Constructor의 중복 Signature에 대해 모른다면..]

하지만 static factory method 를 사용하면 중복 signature 형태도 가능합니다.
예제를 통한 학습이 정말 빠르니깐, 힘들더라도 또 예를 들어볼까 합니다.

public Blog();
public Blog( String powerBloggerID );
public Blog( String blogName ); 


Constructor 를 사용할 경우 2번째와 3번재 있는 Constructor 는 동시에 사용할 수 없습니다.
다시 말해 동시에 정의할 수 없고, compile 에러가 나게 되죠.

하지만 static factory method를 사용하면 다 가능합니다.

public static Blog newInstance();
public static Blog newPowerBlogInstanceWithBloggerID( String powerBloggerID );
public static Blog newInstanceWithBlogName( String blogName ); 


물론 저는 급작스럽게 예제를 만드느라 naming 이 누구나 공감할만한 것은 아니라고 생각하지만.
이런식으로 factory method 를 만들 때는 항상 naming 을 고려해야 합니다.
잘못된 naming 으로 확장한 static factory method 는 오히려 혼란을 줄 수도 있죠.


3. 생성자와 달리 호출될 때마다 새로운 객체(instance)를 생성할 필요가 없습니다.


생성자의 목적은 새로운 객체를 생성하는 것이죠. 따라서 생성자를 호출 할때마다 객체 생성을 피할 수 없습니다.
( 생성자에서 에러가 난 경우, 이런 예외 사항들은 우선 접어두고.. )
하지만 static factory method 를 사용하면 기존에 만들어져 있는 객체를 반환하는 방식 ( Singleton )등을 통해
불필요한 객체 생성을 피할 수 있습니다.
이 경우에 equals(Object) 대신에 == 를 통해서 비교를 할 수 있어 성능 향상도 기대할 수 있죠.

객체 생성 계속 생성하면 뭐가 안 좋냐구요?

먼저 새로운 객체 생성은 new 명령어를 통해 만들어 지기 때문에 heap 메모리를 차지하게 됩니다.
생성자에서 아무 것도 안 하는 경우에는 "큰" 문제는 안 되겠지만,
생성자에서 무엇을 하느냐에 따라, 경우에 따라서는 객체 하나가 차지하는 메모리 양이 어마어마 할 수 있습니다.
모바일 환경에서는 특히 memory가 부족하기 때문에 불필요한 객체 생성은 피해야 합니다.

게다가 새로운 객체 생성은 꽤나 비중있는 operation입니다.
구현에 따라서 생성자에서 엄청난 작업을 할수도 있습니다.
물론 생성자에서 엄청난 작업을 하는 것이 권장되지 않는 사항이지만, 
남이 만든 class 를 사용해야만 하거나, constructor에서 꼭 작업해야만 한다는 등의 경우를 베재할 수 없습니다.


4. static factory method 는 반환하는 타입의 subtype 도 반환할 수 있습니다.


일반 Constructor 는 자기 자신의 type 만을 반환할 수 있는 반면 
static factory method 는 반환하는 타입의 subtype도 반환할 수 있습니다.

Blog의 Subtype 인 ImageBlog와 VideoBlog가 있다는 가정하에 예를 한번 들어봅니다.

class ImageBlog extends Blog{ ... }
class VideoBlog extends Blog{ ... } 


Constructor는 무조건 자기 자신인 Blog만 Return 할 수 있기 때문에 예를 들 수 없고,
static factory method의 경우만 예를 들어 보았습니다.

public static Blog newInstance( String type ){

if ( type.equals( "Image" )

return new ImageBlog();

else if ( type.equals( "video" )

return new VideoBlog();

return null;

}  


이런 게 가능하다는 말이죠.


그럼 static factory method 의 단점은 없어요?


Naming 만 충실히 하면 큰 단점은 없다고 보여집니다.
하지만 naming 이 부실할 경우 다른 static method 들과 static factory method를 쉽게 구별하지 못 할 수도 있죠.
게다가 정확한 naming 없이 필요 이상으로 과다하게 static factory method 를 만들 경우에는 혼란을 야기하기도 합니다.
그래서 naming을 할 때 보통 newInstance, getInstance 등을 function name 에 곧잘 쓰곤 합니다.




3. Summary


- Static Factory Method 는 constructor 의 역할을 하는 public static function 이다.
 ex) public static Blog newInstance(){ .. }

- 다음과 같은 장점이 있다.

1. 생성자와는 달리 자기 나름의 이름을 가질 수 있다.
2. 중복 Signature Constructor의 형태가 가능하다.
3.  생성자와 달리 호출될 때마다 새로운 객체(Instance)를 생성할 필요가 없다.
4.  반환하는 타입의 subtype도 반환 가능하다.


- Naming 만 잘 지킨다면 큰 단점은 없다.


댓글10

  • 좋은글 2014.08.31 00:21

    좋은글 감사합니다.
    답글

  • 좋은글 2015.06.12 14:30

    물어볼게 하나있는데, 정적 팩토리 메소드 역시 static으로 구현되기 때문에 프로그램 메모리를 잡아 먹고 있지 않나요 ?
    생성할 때 기본적으로 public으로 생성 할 때 보다 이점이 많아 보이긴 하는데, 위 문제에대해서 어떻게 생각하시나요 ㅠㅠ?
    답글

    • 안녕하세요~
      네, static 으로 정의하면 물론 메모리가 조금 더 들 수도 있죠.

      하지만 요즘은 하드웨어들이 너무 잘 나와서 static 함수로 인한 메모리 증가는 메모리 이슈를 논의할만큼은 웬만해서는 안 된다고 생각합니다.

      게다가 static 으로 가능한 녀석들을 instance 함수들로 만든다면, 가독성이나 코드관리 측면 등에서 더 안 좋다고 생각합니다~

  • 인큐벅스 2016.07.18 19:38

    와 책볼때 이해가 안가서 졸렸는데 시원하게 이해가 되네요!!! 감사합니다
    답글

  • 진브로 2016.09.19 14:28

    디자인패턴을 이제부터 배우고 있는 학생입니다.
    굉장히 친절한 내용이라 습득하기가 쉽네요~!
    질문이 하나 있는데, static factory method를 가진 클래스를 상속하고 있는 클래스를 return으로 둘 수 있다고 했는데
    이럴 경우에 결국 반환되는게 생성자여서 힙메모리에 할당되는게 아닌가요??

    아 아니면 static factory method 안에서 생성되는 객체는 한번만 생성해주고 계속해서 생성안되는건가요?
    답글

    • static factory method 에서 원래 주려고 명시한 클래스의 하위 클래스를 return 으로 주는 것을 말씀하시는거죠?
      네, 맞습니다. 새로 생성해서 주게 되면 힙 메모리에 할당이 됩니다.

      static factory method 는 singleton 성격처럼 한번만 생성해서 계속 똑같은 녀석을 줄수도 있고, 매번 새로 생성해서 줄 수도 있습니다.

      상황에 맞게 쓰시면 되고, naming 으로 구분을 하기도 하는데, newInstance 와 같은 형식의 naming 이면 보통 매번 새로 생성해서 주고, getInstance 와 같은 형식의 경우 재사용을 하기도 합니다.

      물론 naming 규칙이라는게 모두가 엄격히 지키는 것은 아니기 때문에, 문서화를 잘 해놓는것이 필요하죠 ^ ^

  • 좋은 글 잘 읽고 갑니다.
    답글