Unreal_Engine🎮/TIL📖

[ Unreal Engine ] TIL 📖 ( 8 )

pseonu 2025. 1. 7. 23:37

챕터 3-1 디자인 패턴

 

디자인 패턴이란? 

=> 개발 중 자주 나타나는 문제를 해결하기 위한 일반화 된, 재사용 가능한 솔루션 

 

 

디자인 패턴은 세가지 유형으로 나뉜다.

1. 생성 패턴 (Creational Patterns)
2. 구조 패턴 (Structual Patterns)
3. 행동 패턴 (Behavioral Patterns)

1. 생성 패턴 (Creational Patterns)

 

생성 패턴은 객체 생성 과정을 캡슐화 하거나, 객체 생성의 복잡성을 숨기고 코드를 유연하게, 재사용성을 높이는데 중점을 두는 패턴이다. 공장에서 물건을 찍어내듯이 객체를 찍어냄.

 

예시로는 싱글톤, 팩토리 메서드, 추상 팩토리, 빌더, 프로토타입 등이 있다.

 

Ex) 싱글톤

하나의 인스턴스만 존재해야 함.

모든 호출자가 같은 인스턴스를 공유해야 한다.

 

ex) 로깅 시스템, 데이터베이스 연결 풀, 설정 관리

class Singleton {
private:
    static Singleton* instance;
    Singleton() {} // private 생성자
public:
    static Singleton* getInstance() {
        if (!instance) instance = new Singleton();
        return instance;
    }
};

 

프로젝트 전체에서 하나의 인스턴스를 공유하므로, 어떤 코드에서든 동일한 객체에 접근할 수 있다.

객체 상태를 공유하고 유지해야하는 경우 유용함.

 

싱글톤 패턴을 활용한 코드

#include <iostream>
using namespace std;

class Airplane {
private:
    static Airplane* instance; // 유일한 비행기 객체를 가리킬 정적 포인터
    int positionX;             // 비행기의 X 위치
    int positionY;             // 비행기의 Y 위치

    // private 생성자: 외부에서 객체 생성 금지
    Airplane() : positionX(0), positionY(0) {
        cout << "Airplane Created at (" << positionX << ", "<< positionY << ")" << endl;
    }

public:
    // 복사 생성자와 대입 연산자를 삭제하여 복사 방지
    Airplane(const Airplane&) = delete;
    Airplane& operator=(const Airplane&) = delete;

    // 정적 메서드: 유일한 비행기 인스턴스를 반환
    static Airplane* getInstance() {
        if (instance == nullptr) {
            instance = new Airplane();
        }
        return instance;
    }

    // 비행기 위치 이동
    void move(int deltaX, int deltaY) {
        positionX += deltaX;
        positionY += deltaY;
        cout << "Airplane moved to (" << positionX << ", "<< positionY << ")" << endl;
    }

    // 현재 위치 출력
    void getPosition() const {
        cout << "Airplane Position: (" << positionX << ", " << positionY << ")" << endl;
    }
};

// 정적 멤버 초기화
Airplane* Airplane::instance = nullptr;

// 메인 함수 (사용 예시)
int main() {
    // 유일한 비행기 인스턴스를 가져옴
    Airplane* airplane = Airplane::getInstance();
    airplane->move(10, 20);  // 비행기 이동
    airplane->getPosition();

    // 또 다른 요청도 같은 인스턴스를 반환
    Airplane* sameAirplane = Airplane::getInstance();
    sameAirplane->move(-5, 10); // 비행기 이동
    sameAirplane->getPosition();

    return 0;
}

게임 내의 비행기는 오직 한개만 존재한다. 

비행기의 초기 좌표는 ( 0 , 0 ) 이다.

 


2. 구조 패턴(Structual Patterns)

객체와 클래스 간의 관계를 설계하여 시스템의 구조를 단순화하거나 확장성을 높이는 데 중점을 두는 패턴.

 

예시로는 Adapter, Bridge, Composite, Decorator 등이 있다.

 

Ex) Adapter

서로 다른 인터페이스를 가진 클래스를 연결하여 호환성을 제공함. 

class Target {
public:
    virtual void request() = 0;
};

class Adaptee {
public:
    void specificRequest() { cout << "Specific request" << endl; }
};

class Adapter : public Target {
private:
    Adaptee* adaptee;
public:
    Adapter(Adaptee* a) : adaptee(a) {}
    void request() override { adaptee->specificRequest(); }
};

 

데코레이터 패턴을 활용한 코드

#include <iostream>
#include <string>

using namespace std;

// **추상 컴포넌트 (Component): Pizza**
// - 피자 객체의 기본 구조를 정의하는 인터페이스입니다.
// - 모든 피자는 이름(`getName`)과 가격(`getPrice`)을 가져야 합니다.
class Pizza {
public:
    virtual ~Pizza() {}
    virtual string getName() const = 0;  // 피자의 이름 반환
    virtual double getPrice() const = 0; // 피자의 가격 반환
};

// **구체 컴포넌트 (Concrete Component): BasicPizza**
// - 기본 피자 클래스입니다.
// - 피자의 기본 베이스(이름과 가격)를 구현합니다.
class BasicPizza : public Pizza {
public:
    string getName() const {
        return "Basic Pizza"; // 기본 피자의 이름
    }
    double getPrice() const {
        return 5.0; // 기본 피자의 가격
    }
};

// **데코레이터 추상 클래스 (Decorator): PizzaDecorator**
// - 기존 피자의 기능을 확장하기 위한 데코레이터의 기본 구조를 정의합니다.
// - 내부적으로 `Pizza` 객체를 감싸며, 이름과 가격에 추가적인 기능을 제공합니다.
class PizzaDecorator : public Pizza {
protected:
    Pizza* pizza; // 기존의 피자 객체를 참조합니다.
public:
    // 데코레이터는 피자 객체를 받아서 감쌉니다.
    PizzaDecorator(Pizza* p) : pizza(p) {}
    
    // 소멸자에서 내부 피자 객체를 삭제합니다.
    virtual ~PizzaDecorator() {
        delete pizza;
    }
};

// **구체 데코레이터 (Concrete Decorators): Cheese, Pepperoni, Olive**
// - 각각의 토핑 데코레이터는 `PizzaDecorator`를 상속받아 이름과 가격을 확장합니다.

// 치즈 토핑 데코레이터
class CheeseDecorator : public PizzaDecorator {
public:
    CheeseDecorator(Pizza* p) : PizzaDecorator(p) {}
    string getName() const {
        // 기존 피자의 이름에 " + Cheese"를 추가
        return pizza->getName() + " + Cheese";
    }
    double getPrice() const {
        // 기존 피자의 가격에 치즈 추가 비용 1.5를 더함
        return pizza->getPrice() + 1.5;
    }
};

// 페퍼로니 토핑 데코레이터
class PepperoniDecorator : public PizzaDecorator {
public:
    PepperoniDecorator(Pizza* p) : PizzaDecorator(p) {}
    string getName() const {
        // 기존 피자의 이름에 " + Pepperoni"를 추가
        return pizza->getName() + " + Pepperoni";
    }
    double getPrice() const {
        // 기존 피자의 가격에 페퍼로니 추가 비용 2.0을 더함
        return pizza->getPrice() + 2.0;
    }
};

// 올리브 토핑 데코레이터
class OliveDecorator : public PizzaDecorator {
public:
    OliveDecorator(Pizza* p) : PizzaDecorator(p) {}
    string getName() const {
        // 기존 피자의 이름에 " + Olive"를 추가
        return pizza->getName() + " + Olive";
    }
    double getPrice() const {
        // 기존 피자의 가격에 올리브 추가 비용 0.7을 더함
        return pizza->getPrice() + 0.7;
    }
};

// **클라이언트 코드**
// - 피자와 데코레이터를 조합하여 최종 피자를 생성하고, 정보를 출력합니다.
int main() {
    // 1. 기본 피자를 생성합니다.
    Pizza* pizza = new BasicPizza();

    // 2. 치즈 토핑을 추가합니다.
    pizza = new CheeseDecorator(pizza);

    // 3. 페퍼로니 토핑을 추가합니다.
    pizza = new PepperoniDecorator(pizza);

    // 4. 올리브 토핑을 추가합니다.
    pizza = new OliveDecorator(pizza);

    // 5. 최종 피자 정보 출력
    cout << "Pizza: " << pizza->getName() << endl; // 피자의 이름 출력
    cout << "Price: $" << pizza->getPrice() << endl; // 피자의 가격 출력

    // 6. 메모리 해제
    delete pizza;

    return 0;
}

피자의 기본 베이스가 필요하고 기본피자엔 이름과 가격이 정의되어 있다.

여기에 토핑을 동적으로 추가 (데코레이터)하여 이름과 비용이 추가됨.

=> 최종 피자의 이름과 가격을 제공 

 


3. 행동 패턴 (Behavioral Patterns)

객체 간의 상호작용과 역할 분담을 정의하여 시스템 동작을 유연하게 만든다.

 

예시로는 Observer, Strategy(전략), Command 등이 있다.

 

Ex) Observer

한 객체의 상태 변화가 여러 객체에 자동으로 통보된다. (이벤트 리스너, 데이터 바인딩 등에 사용됨)

class Observer {
public:
    virtual void update() = 0;
};

class Subject {
private:
    vector<Observer*> observers;
public:
    void attach(Observer* o) { observers.push_back(o); }
    void notify() {
        for (auto o : observers) o->update();
    }
};

 

 

'Unreal_Engine🎮 > TIL📖' 카테고리의 다른 글

[ Unreal Engine ] TIL 📖 ( 10 )  (0) 2025.01.23
[ Unreal Engine ] TIL 📖 ( 9 )  (0) 2025.01.21
[ Unreal Engine ] TIL 📖 ( 6 )  (1) 2024.12.24
[ Unreal Engine ] TIL 📖 ( 5 )  (0) 2024.12.21
[ Unreal Engine ] TIL 📖 ( 4 )  (0) 2024.12.21