자격증/정보처리기사

[정보처리기사 실기 이론] 디자인 패턴 유형 | 행위패턴(Behavioral Patterns) 쉽게 이해하기 - 중재자/인터프리터/이터레이터/템플릿메소드/옵저버/상태/방문자/커맨드/전략/메멘토/책임연쇄

꾸행일기 2025. 7. 16. 08:00

✅ 행위패턴 (Behavioral Patterns) -11가지

행위 패턴은 클래스나 객체 간의 상호작용, 즉 "누가 언제 무엇을 어떻게 수행할 것인가"에 초점을 맞춘 디자인 패턴이다. 객체나 클래스 사이의 책임 분배상호작용을 더 유연하게 만들어주는 패턴들이다.

 

🎯 1. 행위 패턴이란?

객체들의 상호작용(행동)을 조절하는 디자인 패턴의 모음이다.

코드를 효율적으로 만들고, 변경에 유연하게 대응할 수 있도록 도와준다.

  • 초점: “행동을 어떻게 나눌까?”
  • 목적: 결합도를 낮추고, 행동 흐름을 유연하게 만들기
  • 사용 시기: 객체들 간의 복잡한 로직이나 의사소통이 필요할 때

[행 미인이 템옵 스테 비커 스트 매체]

-> 미인이  되어 테이크를 비커에 넣어 스트레이트로 마시다가 메체에 소개되었따. (수제비 책 출처)

패턴 핵심 키워드
중재자
( Mediator)
중앙 소통 관리, 객체 간 간섭 제거
상호 작용의 유연한 변경을 지원
인터프리터
( Interpreter)
문법 해석기, 표현식 계산
구문의 해석을 맡는 클래스를 작성
문법 자체를 캡슐화하여 이용
반복자
( Iterator)
내부구조 은닉하며, 순차적으로 접근 가능
템플릿 메서드
( Template Method)
알고리즘 틀 고정, 세부는 위임
전체구조 변경x, 특정 단계 수행 변경 o
( 상위 작업 구조 바꾸지 않고, 서브 클래스로 작업 일부분 수행)
유지보수 용이
옵저버
( Observer)
변화 감지
한 객체의 상태가 바뀌면 -> 의존하는 객체들 자동으로 변경
일대 다 의존성
상호작용 객체 간 느슨한 결합
상태
( State)
객체 상태를 캡슐화하여 클래스화
객체 상태에 따라 행위 내용변경
변경 시 기존 코드 수정 최소화 -> 유지보수 편의성 증가
방문자
( Visitor)
처리기능 분리하여 별도의 클래스 생성
해당 클래스 메서드(외부회계사가) 각 클래스 돌아다니며(회사마다) 특정 작업 수행(세무조사,감사,보고서작성 등의 기능 수행)
구조는 그대로, 기능만 외부에서 추가 또는 확장
커맨드
( Command)
요청(요구사항)을 객체로 캡슐화, 실행/취소/기록 가능
재사용성 높은 클래스 설계
하나의 추상 클래스에 메서드 만들어 각 명령 들어오면 그에 맞는 서브 클래스 실행
전략
(스트 Strategy)
알고리즘 군 정의하여 같은 알고리즘을 클래스화하여 캡슐화
필요할 때 서로 교환해서 사용 ( 알고리즘 교환 가능 )
즉, 행위 객체를 클래스로 캡슐화하여 동적으로 행위를 자유롭게 바꿀 수 있음
메멘토
( Memento)
상태 저장/복원, 되돌리기
객체 정보 저장 시 적용하는 디자인 패턴
Undo 기능 개발 시 사용
책임 연쇄
( Chain of Responsibility)
순차 처리, 책임 전가 구조
처리할 객체들들 연결고리로 만들어서
요청이오면 각 객체는 내가 처리할 수 있는지 판단 후
못하면 다음 객체에게 넘기는 방식(책임 전가)
(ex.handler)

 

[☞ 생성패턴 공부하러 가기]

[☞ 구조패턴 공부하러 가기


① 중재자 패턴 (Mediator Pattern)

객체 간 복잡한 대화를 중재인이 대신 처리!

🧠 개념

객체들 간의 직접 통신을 막고, 중앙의 중재자 객체가 대신 통신을 관리하게 하는 패턴
→ 복잡한 의존 관계를 깔끔하게 정리할 수 있음

  • 객체 지향 설계에서 객체의 수가 너무 많아지면 서로 간 통신을 위해 복잡해져서 객체 지향에서 가장 중요한 느슨한 결합의 특성을 헤칠 수 있다. 이를 해결하는 방법으로 중간에 이를 통제하고 지시할 수 있는 역할을 하는 중재자를 두고, 중재자에게 모든 것을 요구하여 통신의 빈도수를 줄인다.
  • 상호 작용의 유연한 변경을 지원

💻 쉬운 코드 예시: 수식 계산

// 중재자 인터페이스
interface ChatMediator {
    void sendMessage(String message, User sender);
}

// 유저 클래스
class User {
    String name;
    ChatMediator mediator;

    User(String name, ChatMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    void send(String message) {
        System.out.println(name + " ▶ 메시지 전송: " + message);
        mediator.sendMessage(message, this);
    }

    void receive(String message) {
        System.out.println(name + " ◀ 메시지 수신: " + message);
    }
}

// 중재자 구현체
class ChatRoom implements ChatMediator {
    List<User> users = new ArrayList<>();

    void addUser(User user) {
        users.add(user);
    }

    public void sendMessage(String message, User sender) {
        for (User u : users) {
            if (u != sender) {
                u.receive(message);
            }
        }
    }
}

 

🧪 사용 예시

 

ChatRoom room = new ChatRoom();

User alice = new User("Alice", room);
User bob = new User("Bob", room);
User charlie = new User("Charlie", room);

room.addUser(alice);
room.addUser(bob);
room.addUser(charlie);

alice.send("안녕!");  // Bob, Charlie가 메시지 받음

② 인터프리터 패턴 (Interpreter Pattern)

  • 언어의 다양한 해석, 구체적으로 구문을 나누고, 분리된 구문의 해석을 맡는 클래스를 각각 작성하여ㅠ 여러 형태의 언어 구문을 해석할 수 있게 만드는 디자인 패턴이다.
  • 문법 자체를 캡슐화하여 사용.
// 표현식 인터페이스
interface Expression {
    int interpret();
}

// 숫자 표현식
class Number implements Expression {
    int value;

    Number(int value) {
        this.value = value;
    }

    public int interpret() {
        return value;
    }
}

// 덧셈 표현식
class Plus implements Expression {
    Expression left, right;

    Plus(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 사용예시
Expression expr = new Plus(new Number(2), new Number(3));
System.out.println(expr.interpret()); // 5

③ 반복자 패턴 (Iterator Pattern)

내부 구현을 몰라도 **모든 요소를 하나씩 순회(iterate)**할 수 있게 해주는 패턴
  • 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 반복자를 사용하여 접근할 수 있는 디자인 패턴
  • 내부구조를 노출하지 않고, 복잡 객체의 원소를 순차적으로 접근 가능하게 해주는 행위 패턴
// 간단한 컬렉션
class MyList {
    List<String> items = new ArrayList<>();

    void add(String item) {
        items.add(item);
    }

    Iterator<String> getIterator() {
        return items.iterator();  // Java의 내장 반복자 사용
    }
}

// 사용예시
MyList list = new MyList();
list.add("🍎");
list.add("🍌");
list.add("🍇");

Iterator<String> it = list.getIterator();
while (it.hasNext()) {
    System.out.println("과일: " + it.next());
}

④ 템플릿 메서드 패턴 (Template Method Pattern)

📘 어원

template = 템플릿, 틀
method = 메서드, 동작
→ "전체 알고리즘의 틀은 정의하고, 세부 단계는 서브클래스에 맡기는 구조.

 

🧠 개념

어떤 알고리즘의 골격(템플릿)은 상위 클래스에 정의하고,
그 중 일부 단계를 하위 클래스에서 재정의하는 방식

 

🧃 실생활 비유

라면 끓이는 순서는 같지만,
스프나 재료는 취향 따라 바뀌는 것

 

💻 쉬운 코드 예시

// 추상 클래스: 요리 템플릿
abstract class RamenRecipe {
    final void cook() { // 고정된 순서 (변경 불가)
        boilWater();
        addNoodles();
        addIngredients(); // 이건 사용자 정의
        eat();
    }

    void boilWater() {
        System.out.println("물을 끓입니다.");
    }

    void addNoodles() {
        System.out.println("면을 넣습니다.");
    }

    abstract void addIngredients(); // 서브클래스에서 정의할 부분

    void eat() {
        System.out.println("맛있게 먹습니다.");
    }
}


// 사용자 구현
class SpicyRamen extends RamenRecipe {
    void addIngredients() {
        System.out.println("🌶️ 매운 스프와 고추를 넣습니다.");
    }
}

⑤ 옵저버 패턴 (Observer Pattern)

📘 어원

observe = 관찰하다, 지켜보다
→ "어떤 대상의 상태 변화에 따라 자동으로 반응하는 객체들"

🧠 개념

하나의 객체의 상태가 바뀌면,
그 객체를 관찰하던 다른 객체들에게 자동으로 알려주는 구조

🧃 실생활 비유

  • 유튜브 구독: 새 영상 업로드 시 구독자들에게 알림
  • 날씨 앱: 기상청 데이터 바뀌면 화면도 자동으로 갱신됨

💻 쉬운 코드 예시: 뉴스 발행 시스템

// 옵저버 (구독자)
interface Subscriber {
    void update(String news);
}

// 발행자 (기자)
class NewsAgency {
    List<Subscriber> subscribers = new ArrayList<>();

    void subscribe(Subscriber s) {
        subscribers.add(s);
    }

    void notifyAll(String news) {
        for (Subscriber s : subscribers) {
            s.update(news);
        }
    }
}

// 구독자 구현
class EmailSubscriber implements Subscriber {
    String name;
    EmailSubscriber(String name) { this.name = name; }

    public void update(String news) {
        System.out.println(name + " ▶ 이메일로 뉴스 수신: " + news);
    }
}

🧪 사용 예시

// 사용예시
NewsAgency agency = new NewsAgency();
agency.subscribe(new EmailSubscriber("민수"));
agency.subscribe(new EmailSubscriber("철수"));

agency.notifyAll("📢 새로운 정책 발표!");

⑥ 상태 패턴 (State Pattern)

📘 어원

state = 상태
객체의 상태에 따라 동작이 달라지도록 설계하는 패턴

🧠 개념

객체 내부 상태가 바뀌면,
**행동(메서드 결과)**도 바뀌도록 하는 구조

 

🧃 실생활 비유

  • ATM 기계: 카드가 없을 때 / 있을 때 / 돈 출금 중 → 행동이 다름
  • 신호등: 빨간불, 노란불, 초록불일 때 각기 다른 동작

💻 쉬운 코드 예시

interface State {
    void pressButton();
}

// 상태 A: 대기 상태
class ReadyState implements State {
    public void pressButton() {
        System.out.println("⏯️ 음악 재생 시작");
    }
}

// 상태 B: 재생 중
class PlayingState implements State {
    public void pressButton() {
        System.out.println("⏸️ 음악 일시 정지");
    }
}

// 음악 플레이어 (상태에 따라 행동이 달라짐)
class MusicPlayer {
    State state;

    void setState(State s) {
        this.state = s;
    }

    void pressPlay() {
        state.pressButton();
    }
}

🧪 사용 예시

// 사용예시
MusicPlayer player = new MusicPlayer();

player.setState(new ReadyState());
player.pressPlay(); // ▶ 재생 시작

player.setState(new PlayingState());
player.pressPlay(); // ⏸️ 일시 정지

⑦ 방문자 패턴 (Visitor Pattern)

📘 어원

visit = 방문하다 → “객체에 새로운 기능을 ‘방문자’가 추가해주는 구조”

🧠 개념

객체 구조는 그대로 두고,
기능만 외부에서 분리해서 확장할 수 있게 하는 패턴

🧃 실생활 비유

  • **세무사(방문자)**가 회사(객체)를 방문해서 회계 점검을 해줌
  • 회사 내부는 그대로인데, 방문자가 기능을 더해주는 방식
  • 도형 도색 프로그램 
  • 사각형, 원 등의 도형이 있음
  • 도형 클래스에는 좌표나 크기만 있고, ‘색칠하기’ 기능은 없음
  • 색칠하기 기능을 외부에서 추가하고 싶을 때 → 방문자 패턴 사용!

💻 쉬운 코드 예

📦 1. 방문자 인터페이스 정의

// 방문자: 도형을 방문해서 색칠하는 기능 제공
interface ShapeVisitor {
    void visitCircle(Circle circle);
    void visitRectangle(Rectangle rectangle);
}

 

🧩 2. 도형 공통 인터페이스 정의

// 도형은 모두 이 인터페이스를 구현해야 함
interface Shape {
    void accept(ShapeVisitor visitor);  // 방문자를 받아들임
}
 

🟠 3. 도형 클래스 구현 (Circle, Rectangle)

class Circle implements Shape {
    int radius;

    Circle(int radius) {
        this.radius = radius;
    }

    public void accept(ShapeVisitor visitor) {
        visitor.visitCircle(this);  // 방문자야, 원(Circle)을 처리해줘
    }
}

class Rectangle implements Shape {
    int width, height;

    Rectangle(int w, int h) {
        this.width = w;
        this.height = h;
    }

    public void accept(ShapeVisitor visitor) {
        visitor.visitRectangle(this);  // 방문자야, 사각형을 처리해줘
    }
}​

 

🎨 4. 방문자 구현: 도형을 색칠하는 기능

class PaintVisitor implements ShapeVisitor {
    public void visitCircle(Circle circle) {
        System.out.println("🟠 반지름 " + circle.radius + "인 원을 주황색으로 칠함!");
    }

    public void visitRectangle(Rectangle rect) {
        System.out.println("🟥 " + rect.width + "x" + rect.height + " 사각형을 빨간색으로 칠함!");
    }
}​

🧪 5. 실제 사용 예시

public class Main {
    public static void main(String[] args) {
        // 도형 객체 생성
        Shape circle = new Circle(5);
        Shape rect = new Rectangle(3, 4);

        // 방문자 객체 생성 (색칠 기능)
        ShapeVisitor painter = new PaintVisitor();

        // 도형에 방문자를 전달 (색칠됨!)
        circle.accept(painter);  // 🟠
        rect.accept(painter);    // 🟥
    }
}

🧾 출력 결과

🟠 반지름 5인 원을 주황색으로 칠함!
🟥 3x4 사각형을 빨간색으로 칠함!​

 

✅ 핵심 흐름 요약

  1. 도형은 accept(visitor)를 제공함
  2. 방문자 객체는 visitCircle(circle) 등 도형별 처리 로직을 정의
  3. 도형에 방문자를 전달 → 도형의 구조는 그대로, 기능만 외부에서 처리

⑧ 커맨드 패턴 (Command Pattern)

📘 어원

command = 명령 → “요청(명령)을 객체로 캡슐화해서 실행시기를 제어할 수 있음”

🧠 개념

명령을 객체로 만들어서 요청, 실행, 취소, 기록 등을 유연하게 처리

🧃 실생활 비유

  • 리모컨에 있는 버튼들: 각 버튼이 특정 명령을 수행
  • "실행취소(Undo)", "다시 실행(Redo)" 기능 만들 때 유용

💻 쉬운 코드 예시

 
// 커맨드 인터페이스
interface Command {
    void execute();
}

// 실제 명령: 전등 켜기
class LightOnCommand implements Command {
    public void execute() {
        System.out.println("💡 전등을 켭니다!");
    }
}

// 리모컨 클래스
class RemoteControl {
    Command command;

    void setCommand(Command c) {
        command = c;
    }

    void pressButton() {
        command.execute();
    }
}

🧪 사용 예시

Command lightOn = new LightOnCommand();
RemoteControl remote = new RemoteControl();

remote.setCommand(lightOn);
remote.pressButton(); // 💡 전등을 켭니다!

⑨ 전략 패턴 (Strategy Pattern)

📘 어원

strategy = 전략, 방식 → “행동 방법을 바꿀 수 있도록 알고리즘을 분리”

🧠 개념

알고리즘(행동 방법)을 객체로 분리해서,
필요할 때 전략을 바꿔 쓸 수 있는 구조

🧃 실생활 비유

  • 네비게이션 경로 선택: 가장 빠른 길 / 최소 요금 / 경로 우선 전략 선택
  • 게임 캐릭터가 공격 전략을 바꿀 수 있음

💻 쉬운 코드 예시

// 전략 인터페이스
interface PaymentStrategy {
    void pay(int amount);
}

// 전략 1: 카드 결제
class CardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("💳 카드로 " + amount + "원 결제");
    }
}

// 전략 2: 계좌 이체
class BankTransfer implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("🏦 계좌이체로 " + amount + "원 결제");
    }
}

🛒 결제 컨텍스트 클래스

class Checkout {
    PaymentStrategy strategy;

    void setStrategy(PaymentStrategy s) {
        strategy = s;
    }

    void payBill(int amount) {
        strategy.pay(amount);
    }
}

🧪 사용 예시

Checkout order = new Checkout();

order.setStrategy(new CardPayment());
order.payBill(10000);

order.setStrategy(new BankTransfer());
order.payBill(8000);

⑩ 메멘토 패턴 (Memento Pattern)

📘 어원

memento = 추억, 기억
→ "객체의 상태를 저장해서 되돌릴 수 있는 구조"

🧠 개념

객체의 상태를 저장하고,
나중에 그 상태로 복원(undo) 가능하게 하는 패턴

🧃 실생활 비유

  • Ctrl + Z (실행취소)
  • 게임 저장 & 불러오기 기능

💻 쉬운 코드 예시

// 메멘토: 상태 저장소
class TextMemento {
    String text;

    TextMemento(String text) {
        this.text = text;
    }

    String getText() {
        return text;
    }
}
 

🎨 에디터 클래스 (저장/복원 기능)

class Editor {
    String text = "";

    void write(String newText) {
        text = newText;
    }

    TextMemento save() {
        return new TextMemento(text);
    }

    void restore(TextMemento memento) {
        text = memento.getText();
    }

    void print() {
        System.out.println("📝 현재 텍스트: " + text);
    }
}

🧪 사용 예

Editor editor = new Editor();

editor.write("1차 작성");
TextMemento backup = editor.save(); // 저장
editor.write("2차 수정");

editor.print();         // 📝 2차 수정
editor.restore(backup); // 복원
editor.print();         // 📝 1차 작성

⑪ 책임 연쇄 패턴 (Chain of Responsibility)

📘 어원

chain = 사슬, responsibility = 책임
→ "여러 객체가 책임을 나눠서 처리하고, 조건 안 맞으면 다음에게 넘김"

🧠 개념

요청을 순차적으로 여러 객체에게 넘기면서 처리할 수 있는 구조

 

🧃 실생활 비유

  • 고객센터 전화 → 상담원 1 → 못하면 상급자 → 그래도 안되면 관리자
  • 웹 필터 체인: 인증 → 권한 검사 → 로깅 등

💻 쉬운 코드 예시

abstract class Handler {
    Handler next;

    void setNext(Handler n) {
        next = n;
    }

    void handle(String request) {
        if (next != null) {
            next.handle(request); // 다음으로 넘김
        }
    }
}

// 실제 핸들러
class Manager extends Handler {
    void handle(String request) {
        if (request.equals("문서 결재")) {
            System.out.println("👨‍💼 매니저가 문서를 결재합니다.");
        } else {
            super.handle(request);
        }
    }
}

class Director extends Handler {
    void handle(String request) {
        if (request.equals("예산 승인")) {
            System.out.println("👩‍💼 이사가 예산을 승인합니다.");
        } else {
            super.handle(request);
        }
    }
}

🧪 사용 예시

Handler manager = new Manager();
Handler director = new Director();

manager.setNext(director);

manager.handle("문서 결재"); // 매니저가 처리
manager.handle("예산 승인"); // 매니저 → 이사 처리

 

[☞ 생성패턴 공부하러 가기]

[☞ 구조패턴 공부하러 가기