1: 싱글턴 패턴
싱글턴 패턴은 시스템에서 객체의 유일성을 보장하는 중요한 방법입니다. 이 패턴은 클래스의 생성자를 사적으로 설정하여 외부에서 해당 클래스의 인스턴스를 생성하지 못하게 하고, 전역적으로 유일한 메서드를 제공하여 사용자가 해당 클래스의 인스턴스를 얻도록 합니다.
지연 초기화(.LAZY) 방식 - 스레드 안전 X
지연 초기화 여부: 예 멀티스레드 안전성: 아니오 구현 난이도: 쉬움
이 방식은 가장 기본적인 구현으로, 멀티스레드 환경에서는 제대로 작동하지 않습니다. 동기화(synchronized)가 없으므로 엄밀히 말하면 싱글턴 패턴이라고 할 수 없습니다.
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
지연 초기화(LAZY) 방식 - 스레드 안전 O
지연 초기화 여부: 예 멀티스레드 안전성: 예 구현 난이도: 쉬움
이 방식은 멀티스레드 환경에서도 잘 작동하지만 성능이 다소 저하됩니다. 대부분의 경우에 동기화가 필요 없으나, 처음 호출될 때만 동기화 처리가 이루어집니다.
public class Singleton {
private static Singleton instance;
private Singleton (){}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
즉시 초기화(EAGER) 방식
지연 초기화 여부: 아니오 멀티스레드 안전성: 예 구현 난이도: 쉬움
클래스 로딩 시점에 이미 객체가 생성되기 때문에 멀티스레드 환경에서 안전합니다. 하지만 메모리 낭비가 발생할 수 있습니다.
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return INSTANCE;
}
}
더블 체킹 락(DCL)
JDK 버전: JDK 1.5 이상 지연 초기화 여부: 예 멀티스레드 안전성: 예 구현 난이도: 중간
처음 객체가 생성될 때만 잠시 동기화가 이루어지고 이후에는 동기화가 필요 없습니다.
public class Singleton {
private static volatile Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
2: 빌더 패턴
복잡한 객체를 단계적으로 구성하기 위해 사용되는 패턴입니다. 각 구성 요소와 조립 과정을 분리하여 객체를 순차적으로 생성합니다.
class Pizza {
private String size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
private Pizza(PizzaBuilder builder) {
this.size = builder.size;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.bacon = builder.bacon;
}
public static class PizzaBuilder {
private String size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
public PizzaBuilder setSize(String size) {
this.size = size;
return this;
}
public PizzaBuilder addCheese() {
this.cheese = true;
return this;
}
public PizzaBuilder addPepperoni() {
this.pepperoni = true;
return this;
}
public PizzaBuilder addBacon() {
this.bacon = true;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
}
Pizza pizza = new Pizza.PizzaBuilder()
.setSize("대")
.addCheese()
.addPepperoni()
.addBacon()
.build();
3: 템플릿 메서드
부모 클래스에서 알고리즘의 골격을 정의하고, 자식 클래스에서 구체적인 동작을 재정의하여 다양한 기능을 구현하는 패턴입니다.
abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
public final void play() {
initialize();
startPlay();
endPlay();
}
}
class FootballGame extends Game {
@Override
void initialize() {
System.out.println("축구 게임 초기화!");
}
@Override
void startPlay() {
System.out.println("게임 시작!");
}
@Override
void endPlay() {
System.out.println("게임 종료!");
}
}
4: 프로토타입 패턴
새로운 객체를 만들 때 기존의 객체를 복제하여 새로운 객체를 생성하는 패턴입니다.
public class Prototype implements Cloneable {
private String name;
public Prototype(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}