C++

[강의] 12월 30일 수업정리

k-codestudy 2024. 12. 30. 17:58

오늘은 디자인 패턴에 대한 수업을 들었다.

 

1. 디자인 패턴 

1.1 정의 

  • 디자인 패턴은 개발하면서 발생하는 반복적인 문제들을 어떻게 해결할 것인지에 대한 해결 방안 중 모범 사례이다.
  • 디자인 패턴은 객체 지향 4개 특성 (캡슐화, 상속, 추상화, 다형성)과 설계 원칙(SOLID)을 기반이다.

간단히 말하면, 클래스를 설게 할 때 참고할 수 있는 구조적 예시이다.

하지만 우리 C++의 경우,  일반적인 디자인 패턴을 가지고 오면 메모리 누수가 발생하기에 프로그래머가 수동으로 메모리 누수를 잡아야 한다.

 

 

1.2 스트래티지 패턴 vs 스테이트 패턴

 

스트래티지 패턴

  • 정의: 알고리즘을 캡슐화하여 실행 중에 교체할 수 있도록 설계하는 패턴.
  • 특징: 외부에서 알고리즘(전략)을 선택하고 변경합니다.
  • 사용 예: 사용자가 직접 무언가를 변경(예: "날 수 있는 기능"으로 교체) 해야 하는 경우.
  • 핵심 포인트: 외부에서 결정된 전략으로 행동이 바뀝니다.

 

스테이트 패턴

  • 정의: 객체의 상태를 캡슐화하여, 상태에 따라 객체의 동작이 자동으로 변경되도록 설계하는 패턴.
  • 특징: 객체의 내부 상태가 스스로 변하며 동작도 변경됩니다.
  • 사용 예: "이 상태가 되면 행동이 자동으로 변해야 한다"는 경우.
  • 핵심 포인트: 내부 상태 변화에 따라 행동이 바뀝니다.

strategy pattern / state pattern

 

[차이점 정리]

스트래티지                                                 스테이트 

주체 외부에서 행동 방식을 선택 내부 상태 변화에 따른 자동 행동 변경
행동 변경 방식 사용자가 직접 교체 상태 변화에 따라 내부에서 자동 변경
주요 사례 "날기", "헤엄치기" 기능을 교체 "잠", "깨어남" 상태에 따른 행동 변화

 

  • 스트래티지 패턴: 외부에서 "이제 이걸로 바꿔라." (ex: 업그레이드 시 사용자 명령으로 교체)
  • 스테이트 패턴: 내부에서 "상태가 바뀌었으니 이 동작으로 변경." (ex: 상태 변화에 따라 자동으로 행동 변경)

 

 

1.3 데코레이터 패턴 

  • 정의 :데코레이터 패턴은 객체를 특수 래퍼 객체에 감싸서 새로운 기능을 추가하거나 확장할 수 있도록 하는 구조적 디자인 패턴
  • 이 패턴은 중복 허용이 가능하며, 기존 클래스의 수정 없이 기능을 동적으로 확장할 수 있다

Decorator patten

위에 UML을 구현해 보겠다.

 

1.3.1 구현

 

Beverage.h 

  • 음료의 기본 인터페이스(I_BEVERAGE)와 추상 클래스(C_BEVERAGE)를 정의
#pragma once

#include "stdio.h"

__interface I_BEVERAGE
{
	void print();
	int getCost();
};

class C_BEVERAGE abstract : public I_BEVERAGE
{
private:


public:
	C_BEVERAGE() = default;
	virtual ~C_BEVERAGE() = default;
};

 

Decaf.h / cpp

  • 기본 음료 클래스 ( Decaf )
#pragma once
#include "beverage.h"

class C_DECAF : public C_BEVERAGE
{
public:
	void print() override;
	int getCost() override;
};

#include "decaf.h"

void C_DECAF::print()
{
    printf("디카페인\n");
}

int C_DECAF::getCost()
{
    return 600;
}

Espresso.h / cpp

  • 기본 음료 클래스 ( Espresso )
#pragma once
#include "beverage.h"

class C_ESPRESSO : public C_BEVERAGE
{
public:
	void print() override;
	int getCost() override;
};

#include "espresso.h"

void C_ESPRESSO::print()
{
    printf("에스프레소\n");
}

int C_ESPRESSO::getCost()
{
    return 500;
}

Decorator.h / cpp

  • 데코레이터는 음료 객체(C_BEVERAGE)를 포인터로 참조하며, 새로운 기능을 추가
#pragma once

#include "beverage.h"

class C_DECORATOR abstract : public C_BEVERAGE
{
protected:
	C_BEVERAGE* m_pBeverage; 
public:
	C_DECORATOR(C_BEVERAGE* pBeverage);
	~C_DECORATOR();
};

#include "decorator.h"

C_DECORATOR::C_DECORATOR(C_BEVERAGE* pBeverage) :
	m_pBeverage{}
{
	m_pBeverage = pBeverage;
}

C_DECORATOR::~C_DECORATOR()
{
	delete m_pBeverage;
}
  • C_BEVERAGE* m_pBeverage :
    핵심으로 decorator가 beverage를 알고 있어야 함, 그렇기에 생성자에서 생성할 때 꽂아줘야 한다 
  • 그리고 생성자에서 생성을 했으니 주기를 맞추기 위해 소멸자에서 delete를 하여 메모리 누수를 막음

Milk.h / cpp ( milk, mocha, whip 구조가 똑같아 하나만 적어놓음 )

#pragma once
#include "decorator.h"

class C_MILK : public C_DECORATOR
{
public:
	C_MILK(C_BEVERAGE* pBeverage);
	void print() override;
	int getCost() override;
};


#include "milk.h"

C_MILK::C_MILK(C_BEVERAGE* pBeverage) :
    C_DECORATOR(pBeverage)
{
}

void C_MILK::print()
{
    m_pBeverage->print();
    printf("우유\n");
}

int C_MILK::getCost()
{
    return m_pBeverage->getCost() + 400;
}

 

main.cpp

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <iostream>

#include "decaf.h"
#include "espresso.h"
#include "milk.h"
#include "mocha.h"
#include "whip.h"

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	C_BEVERAGE* pBeverage = new C_ESPRESSO{};

	pBeverage = new C_MILK(pBeverage);
	pBeverage = new C_MOCHA(pBeverage);
	pBeverage = new C_MOCHA(pBeverage);
	pBeverage = new C_WHIP(pBeverage);
	pBeverage = new C_WHIP(pBeverage);

	pBeverage->print();
	printf("%d\n", pBeverage->getCost());

	delete pBeverage;
}

 

1.3.2 동작 원리

생성:

  • 음료 객체(예: C_ESPRESSO)를 생성
  • 데코레이터 객체(예: C_MILK)는 생성자로 기존 객체를 받아 내부에 저장.

연쇄 연결:

  • 각 데코레이터는 원본 객체를 포함하며, 새로운 기능을 추가
  • 데코레이터끼리 연쇄적으로 연결

소멸:

  • delete를 호출하면, 소멸자가 재귀적으로 호출되며 모든 객체가 해제

 

'C++' 카테고리의 다른 글

[강의] 1월 2일 수업정리  (0) 2025.01.02
[강의] 12월 31일 수업정리  (0) 2024.12.31
[강의] 12월 27일 수업정리  (0) 2024.12.27
[강의] 12월 26일 수업정리  (1) 2024.12.26
[강의] 12월 24일 수업정리  (0) 2024.12.25