회사에서 다양한 패턴에 대해 공부하는 시간이 있어
시간을 들여 정리해 보았습니다.
템플릿 메서드 패턴
틀은 내가 정해줄게! 너는 세부만 채워~!
상위 클래스(추상 클래스) 에 알고리즘의 전체 구조를 정의해 놓고, 세부 단계는 하위 클래스가 구현하도록 하는 패턴입니다.
예시
1. 게임 로딩
2. 로그인
3. 캐릭터 생성 or 불러오기 ← 이것만 다름!
4. 게임 시작
// 추상 클래스 (틀)
abstract class GameTemplate {
public final void startGame() {
load();
login();
characterSelect(); // <- 자식이 구현
play();
}
private void load() {
System.out.println("🔃 게임 로딩");
}
private void login() {
System.out.println("🔐 로그인");
}
protected abstract void characterSelect();
private void play() {
System.out.println("🎮 게임 시작!");
}
}
// 자식 클래스 A
class WarriorGame extends GameTemplate {
protected void characterSelect() {
System.out.println("🗡️ 전사 캐릭터 선택");
}
}
// 자식 클래스 B
class MageGame extends GameTemplate {
protected void characterSelect() {
System.out.println("🪄 마법사 캐릭터 선택");
}
}
// 실행
public class Main {
public static void main(String[] args) {
GameTemplate game = new WarriorGame();
game.startGame();
System.out.println("\n-----\n");
game = new MageGame();
game.startGame();
}
}
전략 패턴
전략(방법)은 바꿔 쓸 수 있어!!
알고리즘을 인터페이스로 분리해서, 필요에 따라 런타임에 서로 다른 전략으로 바꿔서 쓸 수 있는 패턴입니다.
예시
몬스터가 공격할 때, 전략을 다르게 할 수 있습니다.
근접 공격
원거리 공격
마법 공격
// 전략 인터페이스
interface AttackStrategy {
void attack();
}
// 전략 구현체들
class MeleeAttack implements AttackStrategy {
public void attack() {
System.out.println("👊 근접 공격!");
}
}
class RangedAttack implements AttackStrategy {
public void attack() {
System.out.println("🏹 원거리 공격!");
}
}
// 전략을 사용하는 캐릭터
class Character {
private AttackStrategy strategy;
public void setStrategy(AttackStrategy strategy) {
this.strategy = strategy;
}
public void performAttack() {
strategy.attack();
}
}
// 실행
public class Main {
public static void main(String[] args) {
Character character = new Character();
character.setStrategy(new MeleeAttack());
character.performAttack(); // 👊
character.setStrategy(new RangedAttack());
character.performAttack(); // 🏹
}
}
순수 프록시 패턴
진짜 객체 앞에 대리인을 세워서 부가기능을 넣자
원래 기능을 가진 객체 앞에 프록시 객체를 만들어서 로깅, 캐싱, 보안 등 추가 기능을 붙이는 방식입니다.
예시
데이터를 처리하는 Service 가 있는데 실행 전에 로그만 찍고 싶다!
// 실제 서비스
interface Service {
void process();
}
class RealService implements Service {
public void process() {
System.out.println("📦 데이터 처리 중");
}
}
// 프록시
class LoggingProxy implements Service {
private Service target;
public LoggingProxy(Service target) {
this.target = target;
}
public void process() {
System.out.println("📝 [프록시] 처리 전 로그!");
target.process();
System.out.println("📝 [프록시] 처리 후 로그!");
}
}
// 실행
public class Main {
public static void main(String[] args) {
Service realService = new RealService();
Service proxy = new LoggingProxy(realService);
proxy.process(); // 프록시를 통해 실행
}
}
데코레이터 패턴
원래 객체의 기능을 감싸서 계속 추가해나가는 패턴
클래스의 기능을 상속 없이 동적으로 확장하고 싶을 때 사용합니다.
예시
케이크를 만들었는데, 위에 딸기, 초콜릿, 생크림을 얹고 싶다!
점점 하나씩 감싸면서 기능을 추가
// 기본 케이크
interface Cake {
String make();
}
class BasicCake implements Cake {
public String make() {
return "🎂 케이크";
}
}
// 데코레이터 추상 클래스
abstract class CakeDecorator implements Cake {
protected Cake cake;
public CakeDecorator(Cake cake) {
this.cake = cake;
}
}
// 딸기 추가
class Strawberry extends CakeDecorator {
public Strawberry(Cake cake) {
super(cake);
}
public String make() {
return cake.make() + " + 🍓 딸기";
}
}
// 초콜릿 추가
class Chocolate extends CakeDecorator {
public Chocolate(Cake cake) {
super(cake);
}
public String make() {
return cake.make() + " + 🍫 초콜릿";
}
}
// 실행
public class Main {
public static void main(String[] args) {
Cake cake = new BasicCake();
cake = new Strawberry(cake);
cake = new Chocolate(cake);
System.out.println(cake.make());
// 🎂 케이크 + 🍓 딸기 + 🍫 초콜릿
}
}
'Spring' 카테고리의 다른 글
@Aspect - AOP (0) | 2025.05.02 |
---|---|
@Aspect 쓰지 않고 순수 Proxy, Proxy Factory 사용법 (0) | 2025.04.29 |
트랜잭션 프록시와 예외 (0) | 2025.04.08 |
@Transactional , Spring Data JPA 을 같이 쓰는 점에 관하여 (0) | 2025.04.08 |
@PostConstruct , @PreDestory (0) | 2025.03.26 |