반응형
컴포지트 패턴은 어떤 객체들의 집합에 대해 개별 인터페이스를 동일하게 가져갈 수 있게하는 것입니다.
배열에 기반한 속성
크리처의 속성을 배열로 구현하면 작성하기 쉽고 유지 보수 하기도 쉽다.
힘, 민첩, 지능을 가지는 크리쳐의 능력 들의 통계를 내는 구현입니다.
struct Creature
{
int strength, agility, intelligence;
int sum() const {
return strength + agility + intelligence;
}
double average() const {
return sum()/3.0;
}
int max() const {
return max(max(strength, agility), intelligence);
}
}
- 크리처의 속성이 늘어 날때 마다 sum, average, max 구현을 모두 수정해야합니다.
- 구현 도중에 구현을 누락하는 실수를 할 수도 있습니다.
좀더 우화하게 수정할 수 있는 방법이 바로 "배열 기반 속성"입니다.
struct Creature
{
enum Abilities { str, agl, intl, count };
array<int, count> abilities;
int sum() const {
return accumulate(abilities.begin(), abilities.end(), 0);
}
double average() const {
return sum() / (double)count;
}
int max() const {
return *max_element(abilities.begin(), abilities.end());
}
}
그래픽 객체의 그룹핑
서로 다른 객체들을 드래그해서 여러 개 선택해서 마치 하나의 객체처럼 다룹니다.
개별 객체를 렌더링 할 수도 있고 여러 개의 도형을 하나의 그룹으로 렌더링할 수도 있습니다.
struct GraphicObject
{
virtual void draw() = 0;
};
struct Circle : GraphicObject
{
void draw() override
{
std::cout << "Circle" << std::endl;
}
};
struct Group : GraphicObject
{
std::string name;
explicit Group(const std::string& name) : name{name} { }
void draw() override
{
for (auto&& o : objects)
o->draw();
}
std::vector<GraphicObject*> objects;
};
GraphicObject 인터페이스를 구현하여 개별 원이든 그룹 객체든 draw() 함수를 구현하여 그립니다.
Group root("root");
Circle c1, c2;
root.objects.push_back(&c1);
Group subgroup("sub");
subgroup.objects.push_back(&c2);
root.objects.push_back(&subgroup);
root.draw();
뉴럴 네트워크
뉴럴 네트워크의 중심 개념은 뉴런이며 뉴런은 함수와도 같습니다.
어떤 입력에 대해 어떤 출력을 냅니다. 그 출력을 다른 뉴런의 입력으로 연결할 수 있고 그러한 연결이 모여 뉴럴 네트워크를 이룹니다.
뉴런과 뉴련의 연결 구현입니다.
struct Neuron : SomeNeurons<Neuron>
{
vector<Neuron*> in, out;
unsigned int id;
Neuron()
{
static int id = 1;
this->id = id++;
}
};
template<> void connect_to<Neuron>(Neuron& other)
{
out.push_back(&other);
other.in.push_back(this);
}
뉴런과 뉴련 레이어 2개의 종류를 연결하려면 4종류의(뉴런+뉴런, 뉴런+레이어, 레이어+뉴런, 레이어+레이어) connect_to를 구현해야 합니다.
만약 3종류의 연결이라면 9개의 연결을 구현해야 합니다. 이효율적이고 더 나은 방법이 필요합니다.
일일이 연결 함수를 구현하는 대신, 베이스 클래스에 연결 함수를 만들고 다중 상속을 이용합니다.
template <typename Self>
struct SomeNeurons
{
template <typename T> void connect_to(T& other) // 베이스 클래스의 연결 함수
{
for (Neuron& from : *static_cast<Self*>(this))
{
for (Neuron& to : other)
{
from.out.push_back(&to);
to.in.push_back(&from);
}
}
}
};
struct Neuron : SomeNeurons<Neuron> // 베이스 상속
{
vector<Neuron*> in, out;
unsigned int id;
Neuron()
{
static int id = 1;
this->id = id++;
}
Neuron* begin() { return this; }
Neuron* end() { return this + 1; }
};
struct NeuronLayer : vector<Neuron>, SomeNeurons<NeuronLayer> // 베이스와 vector 다중 상속
{
NeuronLayer(int count)
{
while (count-- > 0)
emplace_back(Neuron{});
}
};
Neuron neuron, neuron2;
NeuronLayer layer{ 5 }, layer2{ 2 };
neuron.connect_to(neuron2);
neuron.connect_to(layer);
layer.connect_to(neuron);
layer.connect_to(layer2);
코드 참고 : https://cpp-design-patterns.readthedocs.io/en/latest/
'프로그래밍 일반 > 디자인 패턴' 카테고리의 다른 글
퍼사드 패턴(Façade Pattern) (0) | 2020.01.28 |
---|---|
데커레이터 패턴(Decorator Pattern) (0) | 2020.01.28 |
브릿지 패턴(Bridge Pattern) (0) | 2019.12.08 |
어댑터 패턴(Adapter Pattern) (0) | 2019.12.08 |
싱글턴 패턴(Singleton Pattern) (0) | 2019.12.08 |