👨🏻‍💻 programming/◽ 디자인 패턴

[디자인 패턴] 생성 패턴 - 1. 팩터리 Factory

핑크코냥 2023. 8. 9. 15:03
728x90

** 팩토리 패턴이란? **

🌟 정의

객체를 생성할 때 그 객체의 생성자를 직접 호출하지 않고, 객체 생성을 담담하는 팩토리에 요청하는 구조를 뜻한다.

🌟 장점

1. 객체를 생성하는 코드가 프로그램의 이곳저곳에 산만하게 흩어지지 않고 객체를 생성하는 기능을 한 곳에 모아둘 수 있다.

2. 클래스 타입을 정확히 몰라도 클래스 계층에 맞게 객체를 생성할 수 있다.

3. 팩토리는 클래스 계층에 따라 실행할 수 있다. 

4. 객체를 정확한 순서로 생성하려면 복잡한 단계가 필요하거나, 생성된 객체를 항상 다른 객체와 일정한 방식으로 연결해야 할 때 팩토리를 사용하면 편하다. 


 ** 팩토리 종류 ** 

🌟 정적 팩터리 메서드 (static factory method)

객체를 생성해서 리턴하는 함수.

class Point
{
  // use a factory method
  Point(float x, float y) : x(x), y(y){}
  
public:
  float x, y;

  friend class PointFactory;
};

class PointFactory
{
  static Point NewCartesian(float x, float y)
  {
    return Point{ x,y };
  }

  static Point NewPolar(float r, float theta)
  {
    return Point{ r*cos(theta), r*sin(theta) };
  }
};

 

🔸 여기서 잠깐 !! 🔸

* 팩토리 함수에 static을 사용하는 이유는 뭘까 ? 

객체를 생성하지 않고 static 메서드에 접근이 가능하기 때문이다. static을 사용하면 클래스가 메모리에 올라갈때 이미 자동적으로 생성되기 때문에 인스턴스들이 공통적으로 값을 유지해야할 때 사용한다. 인스턴스가 필요없기 때문에 메서드 호출이 짧아지기 때문에 효율이 올라가는 장점이 있다.

* 메서드란?

어떤 클래스의 멤버함수를 의미한다.

 

🌟 팩터리

객체를 생성하는 함수들을 별도의 클래스에 몰아넣은 클래스를 팩터리라고 한다. 

 

🌟 내부 팩터리

생성할 타입의 내부 클래스로서 존재하는 간단한 팩터리를 말한다. friend 키워드에 해당하는 문법이 없는 프로그래밍 언어들에서는 내부 팩터리를 흔하게 사용하며,  팩터리가 생성해야 할 클래스가 단 한 종일 때 유용하다.

생성할 타입의 내부 클래스이기 때문에 private멤버들에 자동적으로 자유로운 접근 권한을 가진다는 점이 있다. 내부 클래스를 보유한 외부 클래스도 내부 클래스의 private 멤버들에 접근할 수 있다. 

 

🌟 추상 팩터리

여러 종류의 연관 객체들을 생성해야 할 경우사용한다. 

class CarFactory
{
public:
	virtual ~CarFactory() = default;  //항상 가상 소멸자로 정의한다.
	std::unique_ptr<Car> requestCar();
	size_t getNumberOfCarsProduced() const;

protected:
	virtual std::unique_ptr<Car> createCar() = 0;

private:
	size_t mNumberOfCarsProduced = 0;
};

class FordFactory : public CarFactory
{
protected:
	virtual std::unique_ptr<Car> createCar() override;
};

class ToyotaFactory : public CarFactory
{
protected:
	virtual std::unique_ptr<Car> createCar() override;
};


//---------------------------------------------------------------------//

std::unique_ptr<Car> CarFactory::requestCar()
{
	++mNumberOfCarsProduced;
	return createCar();
}

size_t CarFactory::getNumberOfCarsProduced() const
{
	return mNumberOfCarsProduced;
}

std::unique_ptr<Car> FordFactory::createCar()
{
	return std::make_unique<Ford>();
}

std::unique_ptr<Car> ToyotaFactory::createCar()
{
	return std::make_unique<Toyota>();
}

//---------------------------------------------------------------------//

class LeastBusyFactory : public CarFactory
{
public:
	explicit LeastBusyFactory(vector<unique_ptr<CarFactory>>&& factories);
    // explicit 자신이 설정한 방식으로만 객체를 만드려고 할때.
    // 여러 공장을 갖는 LeastBusyFactory 인스턴스를 생성한다.

protected:
	virtual unique_ptr<Car> createCar() override;

private:
	vector<unique_ptr<CarFactory>> mFactories;
};

LeastBusyFactory::LeastBusyFactory(vector<unique_ptr<CarFactory>>&& factories)
	: mFactories(std::move(factories))
{
	if (mFactories.empty())
		throw runtime_error("No factories provided.");
}

unique_ptr<Car> LeastBusyFactory::createCar()
{
	CarFactory* bestSoFar = mFactories[0].get();

	for (auto& factory : mFactories) {
		if (factory->getNumberOfCarsProduced() <
			bestSoFar->getNumberOfCarsProduced()) {
			bestSoFar = factory.get();
		}
	}

	return bestSoFar->requestCar();
}

 

🌟 함수형 팩터리

클래스 대신 함수의 형태로 존재하는 팩터리

class DrinkWithVolumeFactory
{
  map<string, function<unique_ptr<HotDrink>()>> factories;
public:

  DrinkWithVolumeFactory()
  {
    factories["tea"] = [] {
      auto tea = make_unique<Tea>();
      tea->prepare(200);
      return tea;
    };
    factories["Coffee"] = [] {
      auto coffee = make_unique<Coffee>();
      coffee->prepare(10);
      return Coffee;
    };
  }

  unique_ptr<HotDrink> make_drink(const string& name);
};

inline unique_ptr<HotDrink> DrinkWithVolumeFactory::make_drink(const string& name)
{
  return factories[name]();
}

** 출처 **

1. 모던 c++ 디자인 패턴 / 드미트리 네스터룩 지음 / 출판사 : 깃벗
2. 전문가를 위한 c++ (개정 4판) : C++17 / 마크 그레고리 지음 / 출판사 : 한빛 미디어 
728x90