Study/TIL(Today I Learned)

24.09.03 CS, C++

에린_1 2024. 9. 3. 23:26
728x90

24.09.03 CS, C++

CS

추상 팩토리(Abstract Factory)

  • 추상 팩토리 패턴은 연관성이 있는 객체 군이 여러개 있을 경우 이들을 묶어 추상화하고, 어떤 구체적인 상황이 주어지면 팩토리 객체에서 집합으로 묶은 객체 군을 구현화 하는 생성 패턴이다. 클라이언트에서 특정 객체를 사용할 때 팩토리 클래스만을 참조하여 특정 객체에 대한 구현부를 감추어 역할과 구현을 분리시킬 수 있다.
  • 즉, 추상 팩토리의 핵심은 제품군 집합을 타입 별로 찍어낼 수 있다는 점이 포인트이다. 복잡하게 묶이는 제품군들을 관리와 확장하기 용이하게 패턴화 한 것이 추상 팩토리이다.

추상 팩토리 패턴 구조

  • AbstractFactory
    • 최상위 공장 클래스. 여러개의 제품들을 생성하는 여러 메소드들을 추상화 한다.
  • ConcreteFactory
    • 서브 공장 클래스들은 타입에 맞는 제품 객체를 반환하도록 메소드들을 재정의한다.
  • AbstractProduct
    • 각 타입의 제품들을 추상화한 인터페이스
  • ConcreteProduct (Product A - Product B)
    • 각 타입의 제품 구현체들. 이들은 팩토리 객체로부터 생선된다.
  • Client
    • Client는 추상화된 인터페이스만을 이용하여 제품을 받기 때문에, 구체적인 제품, 공장에 대해서는 모른다.

Abstract Factory vs Factory Method

  • 둘다 팩토리 객체를 통해 구체적인 타입을 감추고 객체 생성에 관여하는 패턴 임에는 동일하다. 또한 공장 클래스가 제품 클래스를 각각 나뉘어 느슨한 결합 구조를 구성하는 모습 역시 둘이 유사하다.
  • 그러나 주의할 것은 추상 팩토리 패턴이 팩토리 메서드 패턴의 상위 호환이 아니라는 점이다. 두 패턴의 차이는 명확하기 때문에 상황에 따라 적절한 선택을 해야 한다.
  • 예를들어 팩토리 메서드 패턴은객체 생성 이후 해야 할 일의 공통점을 정의하는데 초점을 맞추는 반면, 추상 팩토리 패턴은 생성해야 할객체 집합 군의 공통점에 초점을 맞춘다.
  • 단, 이 둘을 유사점과 차이점을 조합해서 복합 패턴을 구성하는 것도 가능하다.

추상 팩토리 패턴 특징

  • 패턴 사용 시기
    • 관련 제품의 다양한 제품 군과 함께 작동해야 할때, 해당 제품의 구체적인 클래스에 의존하고 싶지 않은 경우
    • 여러 제품군 중 하나를 선택해서 시스템을 설정해야하고 한 번 구성한 제품을 다른 것으로 대체할 수도 있을 때
    • 제품에 대한 클래스 라이브러리를 제공하고, 그들의 구현이 아닌 인터페이스를 노출시키고 싶을 때
  • 패턴 장점
    • 객체를 생성하는 코드를 분리하여 클라이언트 코드와 결합도를 낮출 수 있다.
    • 제품 군을 쉽게 대체 할 수 있다.
    • 단일 책임 원칙 준수
    • 개방/폐쇄 원칙 준수
  • 패턴 단점
    • 각 구현체마다 팩토리 객체들을 모두 구현해주어야 하기 때문에 객체가 늘어날 때 마다 클래스가 증가하여 코드의 복잡성이 증가한다.(팩토리 패턴의 공통적인 문제점)
    • 기존 추상 팩토리의 세부사항이 변경되면 모든 팩토리에 대한 수정이 필요해진다. 이는 추상 팩토리와 모든 서브클래스의 수정을 가져온다.
    • 새로운 종류의 제품을 지원하는 것이 어렵다. 새로운 제품이 추가되면 팩토리 구현 로직 자체를 변경해야 한다.

C++

  • C++에서는 코드를 효율적으로 관리하고 재사용성을 높이기 위해 헤더 파일(header file)과 소스 파일(source file, .cpp 파일)로 코드를 나눈다. 각각의 파일은 특정한 역할을 하며, 올바르게 사용하면 프로젝트의 유지 보수성과 확장성을 크게 향상시킬 수 있다.

1. 헤더 파일(.h 또는 .hpp 파일)

  • 헤더 파일은 클래스, 함수, 전역 변수, 매크로 등의 선언(declaration)을 포함하는 파일이다. 컴파일러는 헤더 파일을 통해 코드의 구조를 파악하고, 다른 파일에서 이를 사용할 수 있게 한다. 헤더 파일은 보통 .h 또는 .hpp 확장자를 가진다.

헤더 파일의 주요 역할

  • 클래스와 함수의 선언
    • 헤더 파일에는 클래스 정의의 선언부, 함수 프로토타입, 전역 변수의 선언 등이 포함된다.
  • 중복 정의 방지
    • 헤더 파일은 보통 여러 소스 파일에서 포함되기 때문에, 전처리 지시자(preprocessor directive)를 사용하여 중복 포함을 방지해야 한다.

헤더 파일의 구조

  • 일반적인 헤더 파일의 구조는 다음과 같다:
cpp코드 복사
#ifndef MYCLASS_H  // 헤더 가드 시작#define MYCLASS_H

class MyClass {
public:
    MyClass();  // 생성자 선언
    void myFunction();  // 멤버 함수 선언

private:
    int myVariable;  // 멤버 변수 선언
};

#endif  // 헤더 가드 끝

  • 헤더 가드(Header Guard)
    • #ifndef, #define, #endif 지시자를 사용하여 중복 포함을 방지한다. 이는 해당 헤더 파일이 한 번만 포함되도록 보장한다.
  • 클래스 선언
    • MyClass 클래스의 선언을 포함한다. 생성자와 멤버 함수가 선언되지만, 정의는 포함되지 않는다.

헤더 파일에 포함할 내용

  • 헤더 파일에는 주로 다음과 같은 내용이 포함된다:
  1. 클래스 선언
    • 클래스의 멤버 변수와 멤버 함수의 선언만 포함한다.
  2. 함수 프로토타입
    • 함수의 반환형과 매개변수를 포함한 선언만 제공한다.
  3. 전역 변수와 상수 선언
    • extern 키워드를 사용해 전역 변수의 선언을 포함할 수 있다.
  4. 템플릿 선언
    • 템플릿 클래스를 선언하고 정의할 수 있다.
  5. 전처리 매크로
    • 매크로 정의를 통해 상수를 정의하거나 조건부 컴파일을 사용할 수 있다.

2. 소스 파일(.cpp 파일)

  • 소스 파일은 함수와 클래스 멤버 함수의 정의(implementation)를 포함하는 파일이다. 소스 파일은 실제 코드가 실행되는 부분이며, 보통 .cpp 확장자를 가진다.

소스 파일의 주요 역할

  • 함수와 클래스 멤버 함수의 정의
    • 헤더 파일에 선언된 함수와 클래스 멤버 함수의 정의를 포함한다.
  • 코드 로직 구현
    • 소스 파일은 코드의 실제 로직을 구현하며, 컴파일된 결과물에 포함된다.
  • 헤더 파일 포함
    • 소스 파일은 필요한 헤더 파일을 #include 지시자를 사용하여 포함한다.

소스 파일의 구조

  • 일반적인 소스 파일의 구조는 다음과 같다:
cpp코드 복사
#include "MyClass.h"  // 헤더 파일 포함// MyClass 생성자 정의
MyClass::MyClass() {
    myVariable = 0;
}

// MyClass의 멤버 함수 정의
void MyClass::myFunction() {
    // 함수의 실제 코드
}

  • 헤더 파일 포함
    • #include "MyClass.h"와 같은 지시자를 사용하여, 클래스와 함수 선언을 포함하는 헤더 파일을 가져온다.
  • 클래스 멤버 함수 정의
    • MyClass::MyFunction()과 같은 형식으로 멤버 함수가 정의된다. 이 부분에서 실제 함수의 동작을 구현한다.

3. 헤더 파일과 소스 파일의 관계

  • 헤더 파일은 선언(declaration)을 제공하고, 소스 파일은 정의(definition)를 제공한다. 즉, 헤더 파일에는 "어떤 것이 있다"는 정보를 제공하고, 소스 파일은 "어떻게 동작하는지"에 대한 정보를 제공한다.
  • 여러 소스 파일이 같은 헤더 파일을 포함할 수 있다. 이 경우 헤더 가드를 사용해 중복 정의로 인한 컴파일 오류를 방지한다.
  • 소스 파일은 필요한 헤더 파일을 #include 지시자를 사용하여 가져오며, 컴파일 시점에 해당 파일의 내용을 소스 파일에 포함시킨다.

4. #include 지시자

  • #include 지시자는 파일의 내용을 포함시키는 역할을 한다. #include는 두 가지 형태로 사용할 수 있다:
  • #include "MyClass.h": 사용자 정의 헤더 파일을 포함할 때 사용한다. 이 형식은 현재 디렉토리 또는 프로젝트 디렉토리에서 파일을 찾는다.
  • #include <iostream>: 표준 라이브러리 헤더 파일을 포함할 때 사용한다. 이 형식은 컴파일러가 설치된 위치에서 파일을 찾는다.

5. 프로젝트의 구조화

  • C++ 프로젝트를 구조화할 때는 다음과 같은 규칙을 따르는 것이 좋다
  • 헤더 파일과 소스 파일을 분리
    • 각 클래스는 하나의 헤더 파일과 하나의 소스 파일로 구성한다. 예를 들어, Player 클래스가 있다면 Player.h와 Player.cpp 파일을 생성한다.
  • 모듈화(Modularity)
    • 관련된 클래스와 함수는 같은 폴더에 두어 모듈 단위로 관리한다.
  • 헤더 파일 최소화
    • 불필요한 헤더 파일의 포함을 최소화하여 컴파일 시간을 줄인다.

6. 헤더 파일의 상호 참조 문제

  • 두 헤더 파일이 서로를 참조할 때 상호 참조 문제(Circular Dependency)가 발생할 수 있다. 이를 해결하기 위해 전방 선언(forward declaration)을 사용한다. 예를 들어, 클래스 A와 B가 서로 참조해야 하는 경우
cpp코드 복사
// A.h
#ifndef A_H
#define A_H

class B;  // 전방 선언

class A {
    B* b;  // 포인터로 참조
};

#endif  // A_H

cpp코드 복사
// B.h
#ifndef B_H
#define B_H

#include "A.h"  // A.h를 포함class B {
    A* a;  // 포인터로 참조
};

#endif  // B_H

이렇게 하면 상호 참조 문제를 방지할 수 있다.

728x90

'Study > TIL(Today I Learned)' 카테고리의 다른 글

24.09.05 CSAPP복습 ,C++  (0) 2024.09.05
24.09.04 CS, C++  (0) 2024.09.04
24.09.02 CS, 언리얼  (1) 2024.09.02
24.08.30 CS, C++  (0) 2024.08.30
24.08.29 CS, C++  (0) 2024.08.29