public class Singleton {
private static Singleton instance;
private Singleton() {} // 외부에서 생성 못하게 private 생성자
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 최초 1회 생성
}
return instance;
}
}
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
}
}
즉 객체를 직접 생성하지 않고 생성 로직을 하위 클래스에게 위임. 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
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()처럼 호출함
// 구체 팩토리
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();
}
}
즉, 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
}
}