생성 패턴

2025. 5. 30. 22:34·OOP/GoF

Singleton 패턴

더보기

전역에서 하나만 존재하는 객체를 만들고, 모두가 공유하게 하는 패턴

 ex)

🧠 하나의 공유 인스턴스가 필요한 경우 설정 관리자, 로거, DB 커넥션 풀 등
🔒 동기화된 단일 접근점이 필요할 때 예: 리소스 초기화, 상태 저장
📦 전역 상태를 저장하고 싶을 때 캐시, 환경 설정, 앱 전역 플래그 등
public class Singleton {
    private static Singleton instance;

    private Singleton() {} // 외부에서 생성 못하게 private 생성자

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton(); // 최초 1회 생성
        }
        return instance;
    }
}

Builder 패턴

더보기

객체를 생성하는 절차를 단계별로 분리하고, 최종적으로 조합해서 복잡한 객체를 만드는 패턴

많은 필드를 가진 객체를 만들 때 생성자의 가독성을 높일 수 있다. 

ex)
🧩 생성자 파라미터가 너무 많을 때 (5~10개 이상)
🎛 필수/선택 파라미터를 구분하고 싶을 때 setXXX() 말고 깔끔하게
🧱 객체 생성 순서나 조립 과정이 복잡할 때 ex: HTML 파서, DB 쿼리 구성
User user = new User("John", 25, "john@email.com", "Developer", "New York", ...);

 

매개변수  순서 헷갈리고, 선택 필드 생략 불가능, 코드 가독성 ↓

User user = new UserBuilder()
    .setName("John")
    .setAge(25)
    .setEmail("john@email.com")
    .setOccupation("Developer")
    .build();

 

class User {
	private String name;
    private int age;
    private String email;
    
    private User(UserBuilder builder) {
    	this.name= builder.name;
        this.age = builder.age;
        this.email = builder.email;
    }
    
    private String toString() {
    	return name + ", " + age + ", " + email;
    }
    
    // Builder (내부 static 클래스)
    public static class UserBuilder {
    	private String name;
    	private int age;
        private String email;
        
        public UserBuilder setName(String name) {
        	this.name = name;
            return this;
        }
        
        public UserBuilder setAge(int age) {
        	this.age = age;
            return this;
        }
        
        public UserBuilder setEmail(String email) {
        	this.email = email;
            return this;
        }
        
        public User build() {
        	return new User(this);
        }
   	}
}
public class Main {
	public static void main(String[] args){
    	User user = new User.UserBuilder()
        					.setName("Alice")
                            .setAge(30)
                            .setEmail("alice@mail.com")
                            .build();
       	System.out.println(user);  // Alice, 30, alice@mail.com
    }
}

 

 

Factory 메소드

더보기

객체 생성을 메서드로 캡슐화. 객체 생성을 하위 클래스가 결정하도록 하는 패턴

즉 객체를 직접 생성하지 않고 생성 로직을 하위 클래스에게 위임. new 키워드를 직접 사용하는 대신,

객체 생성 부분을 메서드로 분리하여 유연하고 확장 가능한 코드 구조를 만드는 것

 ex)

🧱 객체 생성 과정이 복잡할 때 객체 생성을 한 곳으로 집중하고 캡슐화
🔁 같은 인터페이스지만, 다른 구현체를 선택해야 할 때 예: OS에 따라 다른 버튼 생성
🧩 확장 가능하게 만들고 싶을 때 코드 수정 없이 새로운 타입 추가 가능 (OCP 만족)
// 제품 계층
interface Button {
	void render();
}
class WindowsButton implements Button {
    public void render() {
        System.out.println("Rendering Windows Button");
    }
}

class MacButton implements Button {
    public void render() {
        System.out.println("Rendering Mac Button");
    }
}
// Creator (팩토리 메서드 보유)
abstract class Dialog {
    public void renderWindow() {
        Button okButton = createButton(); // 팩토리 메서드 호출
        okButton.render();
    }

    protected abstract Button createButton(); // 👉 팩토리 메서드
}
// 구체 Creator
class WindowsDialog extends Dialog {
    protected Button createButton() {
        return new WindowsButton();
    }
}

class MacDialog extends Dialog {
    protected Button createButton() {
        return new MacButton();
    }
}
// 클라이언트
public class Client {
    public static void main(String[] args) {
        Dialog dialog = new WindowsDialog(); // 또는 new MacDialog();
        dialog.renderWindow();
    }
}

 

 

팩토리 메서드 vs 추상 팩토리
객체 생성 방식 객체 생성을 하나의 메서드로 캡슐화
단일 제품 (ex. Button 하나)
여러 객체를 하나의 팩토리 객체 내부에 모아놓음
관련 객체 묶음 (제품군 (ex. Button + Checkbox) )
구조 상속 기반 – 하위 클래스가 어떤 객체를 만들지 결정
부모 클래스에서 createProduct() 정의하고, 하위 클래스에서 이를 구현
위임 기반
Factory 객체를 생성해서, factory.createButton()처럼 호출함
결합 상대적으로 낮음 더 낮음 (제품군까지 추상화) 

 

Abstract Factory 패턴

더보기

제품군을 일관되게 생성할 수 있도록 도와주는 팩토리 메소드의 상위 개념

즉, 제품군(Family) 단위로 객체 생성을 추상화

// 제품 계열
interface Button {
    void render();
}

interface Checkbox {
    void check();
}
// Windows 제품군
class WindowsButton implements Button {
    public void render() {
        System.out.println("Windows Button");
    }
}

class WindowsCheckbox implements Checkbox {
    public void check() {
        System.out.println("Windows Checkbox Checked");
    }
}

// Mac 제품군
class MacButton implements Button {
    public void render() {
        System.out.println("Mac Button");
    }
}

class MacCheckbox implements Checkbox {
    public void check() {
        System.out.println("Mac Checkbox Checked");
    }
}
// 추상 팩토리
interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}
// 구체 팩토리
class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new WindowsButton();
    }

    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }

    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}
// 클라이언트
public class Client {
    public static void main(String[] args) {
        GUIFactory factory = new MacFactory(); // 또는 new WindowsFactory()

        Button btn = factory.createButton();
        Checkbox chk = factory.createCheckbox();

        btn.render();
        chk.check();
    }
}

Prototype

더보기

이미 존재하는 객체(프로토타입)를 복사(clone)해서 새로운 객체를 만드는 생성 패턴

즉, new 키워드를 사용하지 않고, 기존 객체를 복제해서 성능을 높이거나 구조를 간단하게 만들기

ex)
🔁 복잡한 객체를 자주 생성해야 할 때 객체 생성 비용이 높거나 복잡할 때, 복제해서 효율적으로 생성
🔀 객체 설정이 유동적일 때 다양한 설정의 객체를 빠르게 복사하고 수정
🧱 객체를 런타임에 동적으로 생성해야 할 때 어떤 클래스인지 모르더라도, 복제만 알면 사용 가능
// 복제 가능한 인터페이스
interface Prototype {
	Prototype clone();
}
// 구체 프로토타입
class Circle implements Prototype {
	private int x, y, radius;
	
	public Circle(int x, int y, int radius) {
		this.x=x;this.y=y;this.radius=radius;
	}
	
	public void draw() {
		System.out.println("Draw Circle at (" + x + "," + y + ") with r=" + radius);
	}
	
	@Override
    public Prototype clone() {
        return new Circle(x, y, radius);  // 얕은 복사
    }
}
// 클라이언트
public class Client {
    public static void main(String[] args) {
        Circle original = new Circle(10, 20, 5);
        Circle copy = (Circle) original.clone();

        original.draw(); // Draw Circle at (10,20) with r=5
        copy.draw();     // Draw Circle at (10,20) with r=5
    }
}

original.clone()을 통해 동일한 속성을 가진 새 객체를 생성할 수 있다. 

 

깊은 복사 vs 얕은 복사

  • 얕은 복사 (Shallow Copy): 참조 값만 복사 (내부 객체는 공유)
  • 깊은 복사 (Deep Copy): 내부 객체까지 복제 (진짜 독립된 객체)

→ 프로토타입 패턴에서는 필요에 따라 deep copy도 구현한다.

'OOP > GoF' 카테고리의 다른 글

구조 패턴  (0) 2025.06.11
행동 패턴  (0) 2025.06.11
'OOP/GoF' 카테고리의 다른 글
  • 구조 패턴
  • 행동 패턴
dev.di
dev.di
devdi 님의 블로그 입니다.
  • dev.di
    개발 블로그
    dev.di
  • 전체
    오늘
    어제
    • 분류 전체보기 (28)
      • Algorithm (9)
        • Basics (9)
      • AWS (0)
        • AWS (0)
        • SAA (0)
      • Computer Science (1)
        • OS 벼락치기 (1)
        • DB 벼락치기 (0)
      • Data Engineer (8)
        • Airflow (0)
        • Data Warehouse (0)
        • Kafka (0)
        • Spark (0)
        • 데브코스 (8)
      • Docker (0)
      • Interviews (1)
      • Network (2)
        • Physical Layer (0)
        • Data Link Layer (0)
      • OOP (3)
        • GoF (3)
      • Python (4)
        • Django (3)
        • Scraping (1)
      • Software Engineering (0)
      • Spring (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    데이터 웨어하우스
    포트포워딩
    IPv4
    sql
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
dev.di
생성 패턴
상단으로

티스토리툴바