TIL_018: 디자인 패턴, 액터(C++)

김펭귄·2025년 8월 21일

Today What I Learned (TIL)

목록 보기
18/93

오늘 학습 키워드

  • 디자인 패턴

  • C++로 액터 만들기

1. 디자인 패턴

  • 개발을 하다보면 반복적으로 직면하는 문제들이 있는데 이를 해결하기 위한 일반화된 솔루션

1-1. Creational Patterns (생성패턴)

  • 새로운 것을 만들어내는 방법과 관련된 패턴

  • 싱글톤 패턴
    생성패턴 중의 하나로 게임에서 플레이어 캐릭터처럼 객체가 하나만 존재해야 할 때 객체를 생성, 사용하는 패턴

class Player {
private:
    static Player* instance; // 유일한 플레이어 객체를 가리킬 정적 포인터
    int level;
    // private 생성자: 외부에서 객체 생성 금지
    Player() : level(1) {}

public:
    // 복사 생성자와 대입 연산자도 삭제 (삭제 대신 private로 만들어도 됨)
    Player(const Player&) = delete;
    Player& operator=(const Player&) = delete;

    // 정적 메서드: 유일한 비행기 인스턴스를 반환
    static Player* getInstance() {
        if (instance == nullptr) 	// 없을 때만 생성
            instance = new Player();
        return instance;			// 있다면 있는 것으로 반환
    }
    void levelUp() { level++; }
    void getLevel() const { cout << level << endl; }
};

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

int main() {
    // 플레이어 새로 생성
    Player* player = Player::getInstance();
    player->levelUp();  
    player->getLevel();

    // 기존 플레이어를 받음
    Player* samePlayer = Player::getInstance();
    player->getLevel();
}

1-2. Structural Patterns (구조패턴)

  • 객체들의 구조를 어떻게 구성할지가 이 패턴의 주 관심사

  • 데코레이터 패턴
    구조패턴 중의 하나로, 기존 객체의 기능을 수정하지 않고, 객체에 새로운 기능을 동적으로 추가하는 디자인 패턴

  • 예를 들어, 에스프레소(기본 커피)에 물을 추가해 아메리카노를 만들고, 우유를 추가해 라떼를 만드는 것처럼, 기능을 계속 추가하면서 객체를 감싸는 구조

  • 단일 책임 원칙(SRP)과 개방-폐쇄 원칙(OCP)을 지키면서 기능 확장성과 유지보수성을 높일 수 있다

  • 구성 요소

    • Component: 기능을 제공할 기본 인터페이스나 추상 클래스
    • ConcreteComponent: 기본 기능을 구현하는 실제 객체
    • Decorator: Component를 상속하거나 구현하는 추상 클래스, 원래 컴포넌트를 감싸는 역할
    • ConcreteDecorator: 실제로 기능을 덧붙이는 클래스들

// 추상 컴포넌트 (Component)
// 피자 객체의 기본 구조를 정의하는 인터페이스입니다.
class Pizza {
public:
    virtual ~Pizza() {}
    virtual string getName() const = 0;  // 피자의 이름 반환
};

// 구체 컴포넌트 (Concrete Component)
// 기본 피자 클래스 정의
class BasicPizza : public Pizza {
public:
    string getName() const {
        return "Basic Pizza"; // 기본 피자의 이름
    }
};

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

// 구체 데코레이터 (Concrete Decorators)
// 각 토핑 데코레이터는 `PizzaDecorator`를 상속받아 이름을 확장
class CheeseDecorator : public PizzaDecorator {
public:
    CheeseDecorator(Pizza* p) : PizzaDecorator(p) {}
    string getName() const {
        // 기존 피자의 이름에 " + Cheese" 추가
        return pizza->getName() + " + Cheese";
    }
};
class PepperoniDecorator : public PizzaDecorator {
public:
    PepperoniDecorator(Pizza* p) : PizzaDecorator(p) {}
    string getName() const {
        // 기존 피자의 이름에 " + Pepperoni"를 추가
        return pizza->getName() + " + Pepperoni";
    }
};

int main() {
    // 1. 기본 피자를 생성합니다.
    Pizza* pizza = new BasicPizza();

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

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

    // 5. 최종 피자 정보 출력
    cout << "Pizza: " << pizza->getName() << endl; 

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

1-3. Behavioral Patterns (행동패턴)

  • 특정 객체가 변할 때 다른 객체들에 이 상태를 어떻게 전달할지에 대한 패턴

  • 옵저버 패턴
    데이터를 관찰하면서 데이터의 변경이 일어날 시 이를 인지하고 그에 맞는 행동을 함

  • Observer를 클래스 내에 vector로 등록하여, 데이터 변경이 일어날 시 각 옵저버들을 호출하여 함수 실행

2. C++로 액터 만들기

  1. C++로 새로운 게임 프로젝트 생성 (경로에 한글 없도록 설정)

  • public으로 생성시, 헤더파일은 public에, cpp파일은 private에 생성됨.
    이러면 프로젝트의 다른 모듈에서도 해당 클래스에 접근 가능

  • private로 생성 시, 헤더파일/cpp 파일 둘 다 private에 생성됨. 해당 모듈에서만 접근 가능

  • 액터가 생성되었으며, BeginPlay()함수에 UE_LOG함수를 통해 게임 시작 시 log를 출력하게 할 수 있다.

  • 생성된 액터는 C++ classes/프로젝트이름/Public에 존재. 아래 사진처럼 Enable Live Coding비활성해야 정상 작동함. 이 액터를 레벨에 마우스로 배치해주면 된다

2-2. 로그 필터

  • Output Log에서 원하는 로그만 볼 수 있게 필터링
  • 아까 LogTemp를 넣어줬으므로 이 단어로 필터링 가능
profile
반갑습니다

0개의 댓글