생성 패턴(Creational Pattern)
- 객체 생성 과정을 추상화하고, 객체 생성을 유연하게 다룰 수 있는 디자인 패턴.
- 객체 생성 과정이 복잡하거나 변경 가능성이 있을 때 유용하게 사용 됨.
- 생성 패턴은 다양한 상황에 따라 객체를 생성하고 구성하는 방법을 정의하며, 객체 생성의 유연성과 재사용성을 증가시킨다.
생성패턴 특징
- 생성패턴은 시스템이 어떤 구체 클래스를 사용하는지에 대한 정보를 캡슐화한다.
- 생성패턴은 이들 클래스의 인스턴스들이 어떻게 만들고 어떻게 서로 맞붙는지에 대한 부분을 완전히 가린다.
객체의 생성과 조합을 캡슐화해 특정 객체가 생성되거나 변경되어도 프로그램 구조에 영향을 크게 받지 않도록 유연성을 제공한다.
생성패턴 종류
-
추상 팩토리 패턴(Abstract factory Pattern)
: 동일한 주제의 다른 팩토리를 묶어 준다.
-
빌더 패턴(Builder Pattern)
: 생성(construction)과 표기(representation)를 분리해 복잡한 객체를 생성한다.
-
팩토리 메서드 패턴(factory Method Pattern)
: 생성할 객체의 클래스를 국한하지 않고 객체를 생성한다.
-
프로토타입 패턴(Prototype Pattern)
: 기존 객체를 복제함으로써 객체를 생성한다.
-
싱글턴 패턴(Singleton Pattern)
: 한 클래스에 한 객체만 존재하도록 제한한다.
추상 팩토리 패턴(Abstract factory Pattern)
추상 팩토리 패턴이란?
- 비슷한 속성의 객체들을 인터페이스로 규격회된 팩토리에서 일관된 방식으로 생성하고,
생성된 객체끼리는 쉽게 교체될 수 있도록 고안된 패턴.
- 추상 팩토리 패턴은 상세화된 서브클래스를 정의하지 않고도 서로 관련성이 있거나 독립적인 여러 객체의 군을 생성하기 위한
인터페이스를 제공.
추상 팩토리 패턴 구조

추상 팩토리 패턴의 장점
- 비슷한 속성의 객체들의 생성과 조합을 추상화하여 일관성 있는 객체 집합을 생성할 수 있다.
- 클라이언트 코드는 추상 팩토리 인터페이스를 통해 객체를 생성하므로 구체적인 클래스에 대한 의존성이 줄어든다.
추상 팩토리 패턴의 단점
- 새로운 종류의 객체를 추가하기 위해서는 새로운 추상 팩토리와 해당하는 구체 팩토리를 추가해야 한다.
팩토리 메서드 패턴과 추상 팩토리 패턴의 차이점
- 객체 생성을 팩토리 메서드는 상속, 추상 팩토리 패턴은 구성으로 만든다.
빌더 패턴(Builder Pattern)
빌더 패턴이란?
- 복잡한 객체를 생성하는 방법을 정의하는 클래스와 표현하는 방법을 정의하는 클래스를 별도로 분리하여,
서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴이다.
- 빌더 패턴은 많은 Optional한 멤버 변수(혹은 파라미터)나 지속성 없는 상태 값들에 대해 처리해야 하는 문제들을 해결한다.
- 팩토리 패턴이나 추상 팩토리 패턴에서 생성해야하는 클래스에 대한 속성 값이 많을 때 아래와 같은 이슈가 있다.
- 클라이언트 프로그램은 팩토리 클래스로 많은 파라미터를 넘겨줄 때 타입, 순서 등에 대한 관리가 어려워져 에러가 발생할 확률이 높아진다.
- 경우에 따라 필요 없는 파라미터들에 대해서 팩토리 클래스에 null 값을 넘겨줘야 한다.
- 생성해야 하는 서브클래스가 무거워지고 복잡해짐에 따라 팩토리 클래스 또한 복잡해진다.
- 빌더 패턴은 위의 문제를 해결하기 위해 별도의 Builder 클래스를 만들어 필수 값은 생성자를 통해, Optional한 값은 메소드를 통해 값을 입력받고
build() 메소드를 통해 최종적으로 하나의 인스턴스를 리턴하는 방식이다.
빌더 패턴 구현 방법
- 빌더 클래스를 Static Nested Class로 생성한다. 이름은 관례적으로 클래스 이름 뒤에 Builder를 붙인다.
- 빌더 클래스의 생성자는 public으로 하며, 필수 값들에 대해 생성자의 파라미터로 받는다.
- Optional한 값들은 각각의 속성마다 메소드로 제공하며, 이때 중요한 것은 메소드의 리턴 값이 빌더 객체 자신이여야 한다.
- 빌더 클래스 내에 build() 메소드를 정의하여 클라이언트 프로그램에게 최종 생성된 결과물을 제공한다. build()로만 객체 생성을 제공하기 때문에
생성 대상이 되는 클래스의 생산자는 private으로 정의해야 한다.
빌더 패턴의 구조

- Director: Builder를 이용하여 객체를 생성(반환)
- Builder: 객체를 생성하는 방법과 형태를 가진 인터페이스
- ConcreteBuilder: Builder 인터페이스의 구현체로 구현하고자하는 각 객체의 특징을 정의
- Product: Director가 Builder를 이용해 생성하는 결과 객체
빌더 패턴의 장점
- 객체들을 단계별로 생성하거나 생성 단계들을 연기하거나 재귀적으로 단계들을 실행할 수 있다.
- 제품들의 다양한 표현을 만들 때 같은 생성 코드를 재사용할 수 있다.
- SRP
빌더 패턴의 단점
팩토리 메서드 패턴이란?
- 팩토리 메서드 패턴은 객체를 생성하기 위해 인터페이스를 정의하지만 어떤 클래스의 인스턴스를 생성할 지에 대한 결정은
서브클래스가 내리도록 할 때 유용하게 사용된다.
- 어떤 클래스가 자신이 생성해야 하는 객체의 클래스를 예측할 수 없을때 사용한다.
- 하위 클래스에서 팩토리 메서드를 오버라이딩해서 객체를 반환하게 하는 패턴.
팩토리 메서드 패턴 구조

- product: 팩토리 메서드가 생성하는 객체의 인터페이스
- ConcreteProduct: product 클래스에 정의된 인터페이스를 실제로 구현하는 클래스
- Creator: product 타입의 객체를 반환하는 팩토리 메서드를 선언하는 클래스
- ConcreteCreator: 팩토리 메서드를 재정의하여 ConcreteProduct의 인스턴스를 반환
팩토리 메소드 패턴의 구현 방법
- Creator를 추상 클래스로 정의하고, 팩토리 메서드는 abstract로 선언하는 방법.
- Creator가 구체 클래스이고, 팩토리 메서드의 기본 구현을 제공하는 방법.
구현시 고려할 점
- 팩토리 메서드에 잘못된 인자가 들어올 경우의 런타임 에러 처리에 대해 고민할 것.
- Enum 등을 사용하는 것도 고려할 필요가 있다.
팩토리 메서드의 장점
- 팩토리 메서드 패턴은 응용프로그램에 국한된 클래스가 코드에 종속되지 않도록 해준다.
- 응용프로그램은 product 클래스에 정의된 인터페이스와만 동작하도록 코드가 만들어지기 때문에, 사용자가 정의한 어떤 ConcreteProduct
클래스가 와도 동작할 수 있다.
- SRP
- OCP
팩토리 메서드의 단점
프로토타입 패턴(Prototype Pattern)
프로토타입 패턴이란?
- 프로토타입은 주로 실제 제품을 만들기에 앞서 대략적인 샘플 의미로 사용되는 단어이다.
- 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정되도록 하며, 인스턴스는 새 객체를 만들기 위해
자기 자신을 복제한다.
- 패턴을 구현하려면 clone() 메소드를 선언하는 추상 클래스를 만든다.
- 다형적 생성자 기능이 필요한 클래스가 있다면 위의 추상 클래스를 상속받게 한 후 clone() 메소드 내의 코드를 구현한다.
프로토타입 패턴의 특징
- 추상 팩토리 패턴과는 반대로 클라이언트 응용 프로그램 내에서 객체 창조자를 서브클래스화 하는것을 피할 수 있게 한다.
- 객체를 생성하는 고유의 비용이 매우 클 때 이 비용을 감내하지 않게 해준다.
프로토타입 패턴의 구조

프로토타입 패턴 적용
- 복사해야 하는 객체들의 구상 클래스들에 코드가 의존하면 안 될 때 사용.
- 각자의 객체를 초기화하는 방식만 다른 자식 클래스들의 수를 줄이고 싶을 때 사용.
프로토타입 패턴 장점
- 객체들을 그 구상 클래스들에 결합하지 않고 복제할 수 있음.
- 반복되는 초기화 코드를 제거한 후 미리 만들어진 프로토타입들을 복제하는 방법으로 사용할 수 있음.
- 복잡한 객체들에 대한 사전 설정들을 처리할 때 상속 대신 사용할 수 있음.
프로토타입 패턴 단점
- 순환 참조가 있는 복잡한 객체들을 복제하는 것은 매우 까다로울 수 있음.
싱글턴 패턴(Singleton Pattern)
싱글턴 패턴이란?
- 인스턴스를 하나만 만들어 사용하기 위한 패턴.
- 커넥션 풀, 스레드 풀, 디바이스 설정 객체 등의 경우 인스턴스를 여러 개 만들게 되면 자원을 낭비하게 되거나 버그를
발생시킬 수 있으므로 오직 하나만 생성하고 그 인스턴스를 사용하도록 하는 것이 목적이다.
- 인스턴스가 하나만 있으니 이 인스턴스에 대한 전역 접근 지점을 제공하는 패턴이다.
싱글턴 패턴의 구조

싱글턴 패턴의 이점
- 인스턴스를 단 하나만 사용하니 메모리 측면에서 이점이 있다.
- 싱글턴 인스턴스가 전역으로 사용되는 인스턴스이기 때문에 다른 클래스의 인스턴스들이 접근하여 사용할 수 있다.
- 전
싱글턴 패턴의 문제점
- 싱글턴 패턴은 한 번에 두 가지 문제를 동시에 해결함으로써 단일 책임 원칙(SRP)을 위반한다.
- 멀티 스레드 환경에서 위험하다.
- 클래스 로더마다 서로 다른 네임스페이스를 정의하기에 클래스 로더가 2개 이상이면 같은 클래스를 여러 번 로딩할 수 있다.
- 리플렉션, 직렬화, 역직렬화도 싱글턴에서 문제가 될 수 있다.
싱글턴 패턴은 안티 패턴?
-
private 생성자를 갖고 있어 상속이 불가능하다.
: 싱글턴은 자신만이 객체를 생성할 수 있도록 생성자를 private으로 제한한다. 하지만 상속을 통해 다형성을 적용하기 위해서는
기본생성자가 필요하므로 객체지향의 장점을 적용할 수 없다.
또한 싱글턴을 구현하기 위해선 객체지향적이지 못한 static 필드와 static 메소드를 사용해야 한다.
-
테스트하기 힘들다.
: 싱글톤은 생성 방식이 제한적이기 때문에 Mock 객체로 대체하기가 어려우며, 동적으로 객체를 주입하기도 힘들다.
테스트 코드를 작성할 수 없다는 것은 큰 단점이 된다.
-
서버 환경에서는 싱글턴이 1개만 생성됨을 보장하지 못한다.
: 서버에서 클래스 로더를 어떻게 구성하느냐에 따라 싱글턴 클래스임에도 불구하고 다른 네임스페이스를 정의하는 클래스 로더들 때문에
1개 이상의 객체가 만들어 질 수 있다. 또한 여러 개의 JVM에 분산돼서 설치되는 경우에도 독립적으로 객체가 생성된다.
-
전역 상태를 만들 수 있기 때문에 바람직하지 못하다.
: 싱글톤의 스태틱 메소드를 이용하면 언제든지 해당 객체를 사용할 수 있고, 전역 상태(Global State)로 사용되기 쉽다.
아무나 객체에 자유롭게 접근하고 수정하며 공유되는 전역 상태는 객체지향 프로그래밍에서 권장되지 않는다.