struct Foo : SomeBase<Foo>
{
...
};
- 베이스 클래스의 구현부에서 this를 하위 타입으로 캐스팅 가능
teamplate<class T> struct Mixin : T
- 계층적으로 여러 타입을 합성
- 각 클래스는 단 하나의 책임을 부여받아 수정을 할 이유 또한 단 하나여야 함
- 기존 코드의 수정 없이 코드를 확장
- 인터페이스에 손을 대지 않고, 그 구현을 통해 기능을 확장 가능하게 만들어져야 함
- 자식 객체에 접근할 때, 그 부모의 인터페이스로 접근해도 문제가 없어야 함
- 필요에 따라 구현할 대상을 선별할 수 있도록 인터페이스를 별개로 두어야 함
- 추상화는 세부사항에 의존해서는 안되며, 그 역이 되어야 함
- 의존성 주입 예시
struct Engine
{
float volume = 5;
int horse_power = 400;
friend std::ostream & operator << (std::ostream & os, const Engine & obj)
{
return os <<
"volume: " << obj.volume <<
"horse_power: " << obj.horse_power;
}
};
struct ILogger
{
virtual ~ILogger() = default;
virtual void Log(const std::string & s) = 0;
};
struct ConsoleLogger : ILogger
{
ConsoleLogger() = default;
void Log(const std::string & s) override
{
cout << "LOG: " << s.c_str() << endl;
}
};
struct Car
{
std::unique_ptr<Engine> engine;
std::shared_ptr<ILogger> logger;
Car(std::unique_ptr<Engine> engine,
const std::shared_ptr<ILogger> & logger) :
engine{ std::move(engine) },
logger{ logger }
{
logger->Log("making a car");
}
friend std::ostream & operator << (std::ostream & os, const Car & obj)
{
return os << "car with engine: " << *obj.engine;
}
};
auto injector = di::make_injector(di::bind<ILogger>().to<ConsoleLogger>());
auto car = injector.create<std::shared_ptr<Car>>();