티스토리 뷰

 

  • 캡슐화 해서 객체 생성하는 디자인 패턴
  • 객체를 생성하는 대신 객체의 인스턴스를 반환한다.
  • 생성자를 직접 사용하는 것을 제한할 수 있다.


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

정적(static)팩토리(factory)메서드(method)
정적 팩토리 메서드란 객체 생성을 담당하는 정적 메서드라는 의미를 가진다.
 
생성자 대신에 메서드로 객체를 생성하는 방식이다.
 

 

정적 팩토리 메서드를 사용하면 좋은 이유?

1. 이름을 지정해서 코드의 가독성이 높아진다.

정적 팩토리 메서드는 목적에 맞게 명확한 이름을 직접 지정할 수 있다.

반면에 생성자는 클래스 이름만 사용하기 때문에, 동일한 클래스에 여러 생성자가 있는 경우 구분하기 어렵다.
 

public class Drink {
    private String name;
    private String type;

    private Drink(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public static Drink createCoffee(String name) {
        return new Drink(name, "coffee");
    }
}

// 클라이언트 코드
Drink coffee = Drink.createCoffee("아메리카노");

예시로 메뉴 이름을 넣으면 종류별로 음료를 등록하는 클래스를 만들어 보았다.

createCoffee라고 커피 메뉴를 만드는 생성 목적을 메서드 이름에 명확하게 적을 수 있어서

목적에 맞게 생성할 수 있고 코드를 봤을 때 한눈에 알아보기 쉽다.

 

 

 

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

인스턴스를 재사용할 수 있도록 만들어 메모리 사용량을 줄일 수 있다.

 

매번 인스턴스를 새로 생성하지 않고,

기존에 만들어둔 인스턴스나, 생성한 인스턴스를 캐싱해서 재활용 해서 불필요한 객체 생성을 방지하고 성능이 향상된다.

public class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {
    }

    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}

// 클라이언트 코드
DatabaseConnection connection1 = DatabaseConnection.getInstance();
DatabaseConnection connection2 = DatabaseConnection.getInstance();

 

같은 요청에는 같은 인스턴스를 반환하는 방식으로 인스턴스의 라이프 사이클을 통제하는 클래스를

인스턴스 통제(instance-controlled) 클래스라 부른다.

 

인스턴스를 통제하면 싱글톤 패턴, 플라이웨이트 패턴을 적용할 수 있다.

 

1. 싱글톤 (Singleton) 패턴

싱글톤 클래스에 전체에서 인스턴스가 하나만 생성하고, 이 인스턴스는 전역적으로 엑세스할 수 있다.

2. 플라이웨이트 (Flyweight) 패턴

객체를 재사용하여 메모리 사용량을 최소화한다.

인스턴스 통제 클래스는 객체 풀에 인스턴스를 보관하고, 요청 시 동일한 객체를 반환해서 불필요한 객체 생성을 막는다.

 


따라서 인스턴스 통제 클래스는

인스턴스를 효율적으로 재사용하거나 제한하여 시스템 리소스를 절약할 수 있고,

동일한 인스턴스에 대해 동일성(identity)를 보장해서 객체 비교에 효율적이라는 장점이 있다.

 

 

 

 

3. 반환 타입이 유연하다.

4. 반환타입의 하위타입을 반환할 수 있다.

정적 팩토리 메서드는 필요에 따라 다양한 객체를 반환할 수 있다. 
 
객체 풀링을 사용하여 이미 생성된 객체를 반환하거나,
싱글턴 패턴을 적용하여 항상 동일한 객체를 반환할 수 있다.

 

이를 통해 클래스 계층 구조를 감추고 인터페이스를 통해 객체를 생성할 수 있다.

public interface Animal {
    void makeSound();
}

public class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Weeee!");
    }
}

public class AnimalFactory {
    public static Animal createCat() {
        return new Cat();
    }
}

// 클라이언트 코드
Animal myPet = AnimalFactory.createCat();
myPet.makeSound(); // "Weeee!"

AnimalFactory.createCat(); 은

정적 정적 팩토리 메서드에서 Return new Cat()으로 정의한 대로 Cat 클래스의 인스턴스를 반환한다.

이 때, Cat 클래스가 implements Animal 로 Animal 인터페이스를 구현하고 있으니까, 반환 타입을 Animal로 지정할 수 있다.

따라서 myPet 변수는 Cat 클래스의 인스턴스를 참조하지만, Animal 인터페이스 타입으로 선언되어 있기 때문에

Animal 인터페이스에서 선언된 makeSound() 메서드를 호출할 수 있다.

 

 

 

5. 하위 클래스 생성 제한

public class ImmutableString {
    //final 을 사용하면 변수는 초기화 후 변경할 수 없게 만들어 불변성을 보장한다.
    private final String value;
	
    //private 접근 제한자를 사용하여 외부에서 직접 생성자를 호출할 수 없게 한다.
    private ImmutableString(String value) {
        this.value = value;
    }
	
    //정적 팩토리 메소드: ImmutableString 인스턴스를 생성하고 반환
    public static ImmutableString fromString(String value) {
        return new ImmutableString(value);
    }
	
    //getter: 객체의 값을 읽을 수 있지만, 수정할 수 없다
    public String getValue() {
        return value;
    }
}

// 클라이언트 코드
ImmutableString myString = ImmutableString.fromString("Hello, world!");

기본 클래스에서 파생된 클래스(하위 클래스)의 인스턴스 생성을 제한할 수 있다.

 

  • 클래스가 final로 선언되면, 그 클래스는 상속될 수 없으며 하위 클래스를 생성할 수 없다.
  • 생성자가 private이거나 protected로 선언되면, 외부에서 직접 객체를 생성할 수 없으므로 하위 클래스 생성이 제한된다.

 

예시로 ImmutableString 클래스는 불변 (immutable) 문자열 객체인 String 타입의 value 필드를 가진다.

*불변 객체: 한 번 생성되면 그 상태를 변경할 수 없다.

따라서 이렇게 생성된 객체는 불변 immutable 하므로, 초기화 후에는 내부의 문자열 값이 변경되지 않는다.

 

 

 

6. 코드를 재사용할 수 있다.

매개변수에 따라 동일한 객체를 반환할 수 있으므로 객체 생성에 대한 코드 중복이 줄어듭니다.
 



 
 

정적 팩토리 메서드의 단점

클래스를 상속할 수 없는 경우가 있고,

정적 팩토리 메서드만 제공하는 클래스는 생성자가 없어 보일 수 있다. 
 

 

 

 

 

반응형