생성자와 정적 팩토리 메소드 차이

hyunwoo·2023년 1월 13일
0

🌳 Java 지식

목록 보기
14/21

우리는 클래스를 정의할 때 보통 아래와 같이 생성자로 정의해 클래스를 다른 곳에서 new로 생성해 사용한다.

public class Test {
	public Test(int x, int y) {
            ...
        }
}

하지만 이와 같이 생성자를 통해 객체를 생성하는 방법은 몇 가지 단점을 가지고 있다.

생성자는 명명을 할 수 없어서 생성자 안에서 별도 전처리 로직이 있을 경우 해당 전처리에서 무엇을 하는지 이해는 해당 생성자 안까지 들어가서 확인을 해야 한다.

이럴 때 정적 팩토리 메소드(Static Factory Method)를 사용한다.

정적 팩토리 메소드(Static Factory Method)란?

생성자를 통해 객체를 생성하는 것이 아닌 별도 메소드를 정의해서 객체를 생성하게 하게 객체 내에 정적 메소드를 정의해놓은 것을 정적 팩토리 메소드라고 한다.

뭔가 팩토리라는 단어가 들어가서 전에 글로 작성했던 팩토리 패턴이랑 비슷하게 느껴질지도 모른다. 하지만 정적 팩토리 메소드와 팩토리 패턴은 명확하게 다른 것이다.

정적 팩토리 메소드는 팩토리 안에서 조건에 따라 분기해서 객체를 생성하는 팩토리 패턴보다는 좀 더 작은 개념으로 객체를 생성하는 팩토리를 메소드로 각각 정의해서 만든 것이다.

예를 들어 아래와 같이 숫자를 넣을 경우 그 숫자 크기에 맞는 배열에 랜덤한 정수 값을 넣어서 사용하는 객체가 있다고 하자.

public class RandomNumberList {
	List<Integer> randomNumber = new ArrayList<>();
    
	public RandomNumberList(int length) {
            for(int i=0; i < length; i++) {
                randomNumber.add((int)(Math.random()*10));
            }
         }

         public RandomNumberList(int length, int min, int max) {
            for(int i=0; i < length; i++) {
                randomNumber.add((int)(Math.random()*(max-min+1) + min));
            }
         }
}
 

생성자를 오버로딩 해서 그냥 배열의 크기를 지정해서 랜덤한 정수 값을 넣는 것과 min, max로 범위를 지정해서 넣는 생성자까지 만들어놨다. 만일 위의 생성자들을 사용한다면 아래와 같을 것이다.

new RandomNumberList(10);
new RandomNumberList(10, 2, 12);

위 코드를 보고 각 생성자가 어떤 것들을 의미하는지 알 수 있을까?

아마 생성자를 통해 객체를 생성하는 것만으로는 각각이 어떤것을 의미하는지 알 수 없을 것이다.

그러면 아래와 같이 생성자를 오버로딩 하는 것이 아닌 메소드로 명명해서 만들면 어떨까?

각 인수가 다른 생성자에 대해서 아래와 같이 명명해서 생성자를 대신하는 메소드를 아래와 같이 만든게 바로 정적 팩토리 메소드이다.

public class RandomNumberList {
	List<Integer> randomNumber = new ArrayList<>();
    
        public static RandomNumberList createWithLenth(int length) {
            RandomNumberList randomNumberList = new RandomNumberList();
            for(int i=0; i < length; i++) {
                randomNumberList.randomNumber.add((int)(Math.random()*10));
            }
            return randomNumberList;
        }

        public static RandomNumberList createWithLenthAndRange(int length, int min, int max) {
            RandomNumberList randomNumberList = new RandomNumberList();
            for(int i=0; i < length; i++) {
                randomNumberList.randomNumber.add((int)(Math.random()*(max-min+1) + min));
              }
            return randomNumberList;
        }
    
}
 

솔직히 위 구조는 그렇게 마음에 드는 구조는 아니지만 이제는 아래와 같이 함수 이름으로 객체를 생성하는 방법에 대해 짐작을 할 수 있게 된다. RandomNumberList의 메소드 안의 로직까지 보지 않아도 메소드 이름만으로 각각 어떤식으로 객체를 생성하는지 짐작할 수 있다.

RandomNumberList.createWithLenth(10);
RandomNumberList.createWithLenthAndRange(10, 2, 12);

또한 위의 명명을 쉽게 할 수 있다는 장점 뿐만 아니라 반환 값을 마음대로 지정할 수 있어서 하위 객체를 반환하는 방식으로도 정적 팩토리 메소드를 사용할 수 있다.

public class mainClass {
	...
        public static mainClass create();
        ...
}

public class subClass implement mainClass {
	...
        public static mainClass create() {
            return new subClass();
        }
        ...
 }

정적 팩토리 메소드의 장점

정적 팩토리 메소드를 구현하는 것은 어렵지 않다. 하지만 어떤 상황에 쓰면 좋고, 어떤 상황에는 쓰면 안 좋은지를 판단하는 것은 조금 어렵다. 우선 정적 팩토리 메소드의 장점을 정리하면 아래와 같다. 해당 장점을 잘 고려해서 정적 팩토리 메소드를 구현해서 사용하자.

  • 객제 생성을 하는 메소드에 명명을 해서 코드를 좀 더 쉽게 이해하게 할 수 있다.

  • 하위 클래스를 반환할 수 있다.

객체를 생성하는 로직을 캡슐화 하는 장점도 있다고 하긴하지만 이는 생성자를 만들어서 그 안에서도 충분히 로직을 구현할 수 있다 생각되어 장점으로 넣지 않았다.

만일 생성자를 오버로딩 해서 구현해야한다거나 하위 클래스를 반환해야 한다면 정적 팩토리 메소드를 사용하면 효과를 볼 수 있을 것이다.

출처: https://pamyferret.tistory.com/31

0개의 댓글