복잡한 서브시스템을 단순한 인터페이스로 감싸는 패턴
→ 사용자가 복잡한 내부 구현을 몰라도 쉽게 기능을 사용할 수 있음.
✅ 예제 (Java)
// 서브시스템 1
class CPU {
void start() { System.out.println("CPU 시작"); }
}
// 서브시스템 2
class Memory {
void load() { System.out.println("메모리 로드"); }
}
// 서브시스템 3
class HardDrive {
void readData() { System.out.println("하드 드라이브에서 데이터 읽기"); }
}
// Facade 클래스 (단순한 인터페이스 제공)
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
public void startComputer() {
cpu.start();
memory.load();
hardDrive.readData();
System.out.println("컴퓨터 부팅 완료!");
}
}
// 사용 예시
public class Main {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.startComputer();
}
}
✔ 사용 예시
알고리즘의 기본 구조(템플릿)는 유지하되, 일부 구현을 서브클래스에서 정의하는 패턴.
→ 공통 로직을 재사용하면서, 각 단계는 다르게 구현 가능.
✅ 예제 (Java)
// 템플릿 클래스 (추상 클래스)
abstract class Game {
abstract void initialize();
abstract void start();
abstract void end();
// 템플릿 메서드 (공통 흐름 정의)
public final void play() {
initialize();
start();
end();
}
}
// 서브 클래스 1
class Soccer extends Game {
void initialize() { System.out.println("축구 게임 준비"); }
void start() { System.out.println("축구 경기 시작"); }
void end() { System.out.println("축구 경기 종료"); }
}
// 서브 클래스 2
class Basketball extends Game {
void initialize() { System.out.println("농구 게임 준비"); }
void start() { System.out.println("농구 경기 시작"); }
void end() { System.out.println("농구 경기 종료"); }
}
// 사용 예시
public class Main {
public static void main(String[] args) {
Game soccer = new Soccer();
soccer.play();
System.out.println("---");
Game basketball = new Basketball();
basketball.play();
}
}
✔ 사용 예시
기본 객체에 동적으로 기능을 추가하는 패턴
→ 상속 없이 객체의 기능을 확장할 수 있음.
✅ 예제 (Java)
// 기본 인터페이스
interface Coffee {
String getDescription();
double cost();
}
// 기본 객체
class BasicCoffee implements Coffee {
public String getDescription() { return "기본 커피"; }
public double cost() { return 5.0; }
}
// 데코레이터 (추가 기능)
class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
public String getDescription() {
return coffee.getDescription() + ", 우유 추가";
}
public double cost() {
return coffee.cost() + 1.5;
}
}
// 사용 예시
public class Main {
public static void main(String[] args) {
Coffee coffee = new BasicCoffee();
System.out.println(coffee.getDescription() + " 가격: " + coffee.cost());
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " 가격: " + coffee.cost());
}
}
✔ 사용 예시
객체 생성을 서브클래스가 담당하도록 하는 패턴.
→ 객체 생성을 캡슐화하여 코드 의존성을 줄임.
✅ 예제 (Java)
// 인터페이스
interface Animal {
void makeSound();
}
// 구현체
class Dog implements Animal {
public void makeSound() { System.out.println("멍멍!"); }
}
// 팩토리 메서드
class AnimalFactory {
public static Animal createAnimal() {
return new Dog();
}
}
// 사용 예시
public class Main {
public static void main(String[] args) {
Animal animal = AnimalFactory.createAnimal();
animal.makeSound();
}
}
✔ 사용 예시
서로 관련된 객체군을 생성하는 팩토리 패턴
→ 인터페이스를 사용해 여러 종류의 객체 생성을 캡슐화함.
✅ 예제 (Java)
// 버튼 인터페이스
interface Button {
void render();
}
// 윈도우 버튼
class WindowsButton implements Button {
public void render() { System.out.println("윈도우 버튼"); }
}
// 맥 버튼
class MacButton implements Button {
public void render() { System.out.println("맥 버튼"); }
}
// 팩토리 인터페이스
interface GUIFactory {
Button createButton();
}
// 윈도우 팩토리
class WindowsFactory implements GUIFactory {
public Button createButton() { return new WindowsButton(); }
}
// 맥 팩토리
class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
}
// 사용 예시
public class Main {
public static void main(String[] args) {
GUIFactory factory = new WindowsFactory();
Button button = factory.createButton();
button.render();
}
}
✔ 사용 예시
객체 간의 복잡한 관계를 중앙에서 관리하는 패턴.
→ 객체 간 직접적인 의존성을 줄여 유지보수성을 높임.
트리 구조로 객체를 구성하고, 개별 객체와 그룹을 동일하게 다룰 수 있도록 하는 패턴.
→ 예: 파일 시스템 (파일과 폴더를 동일하게 다룰 수 있음)
🚀 마무리
디자인 패턴을 적절히 활용하면 코드의 유지보수성, 확장성, 가독성이 향상됩니다.