본문 바로가기
개발/Architecture & Design Pattern

C++ - 반복자, 이터레이터 패턴 (Iterator Pattern)

by 피로물든딸기 2024. 2. 4.
반응형

C, C++ 전체 링크

Architecture & Design Pattern 전체 링크

 

참고

- 연산자 오버로딩을 이용하여 구조체 출력하기

- 클래스 다이어그램 그리기

- 스마트 포인터 : unique_ptr

 

반복자, 이터레이터 패턴 (Iterator Pattern) - 행동 패턴

- 객체의 컬렉션을 순회하고 요소에 접근할 수 있는 방법을 제공하는 패턴

- 컬렉션의 요소에 대한 구체적인 구현을 노출시키지 않고 컬렉션을 순회

 

구현

- Iterator (반복자) : 컬렉션의 요소를 순회하고 접근하는 인터페이스, next()hasNext()를 제공

- ConcreteIterator : Iterator 인터페이스를 구현하여 실제 컬렉션에 대한 순회 및 접근 동작 구현

- Aggregate (집합체) : 어떤 자료 구조를 활용하여 모아둔 객체, 컬렉션

  ㄴ 요소들의 집합을 나타내는 인터페이스를 정의, 이터레이터를 생성하는 메서드를 포함

- ConcreteAggregate : Aggregate 인터페이스를 구현, 이터레이터를 생성하는 메서드를 구현

 

장점

- SRP(단일 책임 원칙), 순회 알고리즘을 별도의 클래스로 구분하여 클라이언트 코드와 분리한다.

- OCP(개방-폐쇄 원칙), 새로운 컬렉션을 구현하더라도 기존 코드를 건드릴 필요가 없다.

- 컬렉션의 내부 구조를 숨기기 때문에 클라이언트 코드가 단순해진다.

- 컬렉션의 내부 구조를 변경하더라도 클라이언트 코드를 변경하지 않고 순회 알고리즘을 유지한다.

- 컬렉션 순회 코드를 재사용할 수 있고 다양한 순회 방법을 제공할 수 있다.

 

단점

- 일부 구현에서 추가 오버헤드가 발생할 수 있다.

- 특정 언어에서는 반복자를 지원하지 않을 수도 있다.


빌딩 관리

 

건물주가 빌딩을 관리하려고 한다.

BuildingInfo 클래스에는 몇 층에 누가 그 건물에 임대 또는 거주하고 있는지에 대한 정보를 가지고 있다.

class BuildingInfo
{
public:
	BuildingInfo() = default;
	BuildingInfo(int f, string n) : floor(f), name(n) {}
	int getFloor() { return floor; }
	string getName() { return name; }

private:
	int floor;
	string name;
};

ostream& operator<<(ostream& os, BuildingInfo& b)
{
	os << "(" << b.getFloor() << ") [ " << b.getName() << " ]";
	return os;
}

 

건물주(클라이언트)모든 건물의 정보에 일일이 접근하려고 한다.

아파트 배열(or array)로 만들어져있고, 오피스텔vector로 구현되었다.

건물주는 건물이 어떻게 구현되고 저장되는지와 관련 없이 모든 건물에 접근하려고 한다.

 

위에서 언급한대로 Apart배열로 구현되어 있다.

class Apart
{
public:
	Apart() { ... }
	void addFloor(int f, string n) { ... }
	BuildingInfo* getFloors() { return floors; }
    
private:
	static constexpr size_t MAX_FLOOR = 10;
	size_t floorCount = 0;
	BuildingInfo floors[MAX_FLOOR];
};

 

Officevector로 구현되어 있다.

class Office
{
public:
	Office() { ... }
	void addFloor(int f, string n) { ... }
	vector<BuildingInfo>& getFloors() { return floors; }
    
private:
	vector<BuildingInfo> floors;
};

 

ApartOfficefloors가 각각 다르게 구현되어 있기 때문에 floors 값을 받아 매번 새롭게 구현을 해야 한다.

그리고 구현을 위해 각 항목의 컬렉션이 구체적으로 어떻게 표현되는지 알아야 한다. (캡슐화 X)

	// apart와 office 순회가 서로 다르게 구현
    
	BuildingInfo* apartFloors = apart->getFloors();	
	for (int i = 0; i < 3 /* or getSize() */ ; i++) cout << apartFloors[i] << endl;

	vector<BuildingInfo>& officeFloors = office->getFloors();
	for (BuildingInfo b : officeFloors) cout << b << endl;

 

반복자, 이터레이터 패턴을 이용해 아파트와 오피스를 모두 같은 방식으로 접근해보자.


Iterator Interface

 

반복 작업을 처리하는 방법을 Iterator 객체로 만들면 반복을 캡슐화 할 수 있다.

다음 객체가 있는 동안( while(hasNext()) ) 객체를 처리하고 next()로 다음 객체로 넘어간다.

 

이제 ApartIterator를 구현한 후, Apart에서 내부 구조를 드러내는 getFloors()는 삭제한다.

그리고 makeIterator이터레이터를 생성하는 메서드를 추가한다.

class ApartIterator : public Iterator<BuildingInfo>
{
public:
	static constexpr size_t MAX_FLOOR = 10;
	ApartIterator(BuildingInfo* b, size_t size) : buildingInfo(b), size(size) {}
	BuildingInfo* next() override { return &buildingInfo[index++]; }
	bool hasNext() const override { return size > index && buildingInfo[index].getName() != ""; }

private:
	BuildingInfo* buildingInfo;
	size_t index = 0;
	size_t size;
};

class Apart
{
public:
	Apart() { ... }
	void addFloor(int f, string n) { ... }
    
	unique_ptr<Iterator<BuildingInfo>> makeIterator() { return make_unique<ApartIterator>(floors, floorCount); }

private:
	static constexpr size_t MAX_FLOOR = 10;
	size_t floorCount = 0;
	BuildingInfo floors[MAX_FLOOR];
};

 

배열 대신 C++ <array>를 이용해서 구현하면 아래와 같다.

class ApartIterator : public Iterator<BuildingInfo>
{
public:
	static constexpr size_t MAX_FLOOR = 10;
	ApartIterator(array<BuildingInfo, MAX_FLOOR> &b) : buildingInfo(b) {}
	BuildingInfo* next() override { return &buildingInfo[index++]; }
	bool hasNext() const override { return buildingInfo.size() > index && buildingInfo[index].getName() != ""; }

private:
	array<BuildingInfo, MAX_FLOOR> &buildingInfo;
	array<BuildingInfo, MAX_FLOOR>::size_type index = 0;
};

class Apart
{
public:
	Apart() { ... }
	void addFloor(int f, string n) { ... }

	unique_ptr<Iterator<BuildingInfo>> makeIterator() { return make_unique<ApartIterator>(floors); }

private:
	static constexpr size_t MAX_FLOOR = 10;
	size_t floorCount = 0;
	array<BuildingInfo, MAX_FLOOR> floors;
};

 

이제 건물주(Manager)는 ApartOffice이터레이터에 접근해서 각 건물 정보를 출력하면 된다.

class Manager
{
public:
	Manager(Apart* apt, Office* ofc) : apart(apt), office(ofc) {}
    
	void printAll() { ... }
	void printBuildingInfo(Iterator<BuildingInfo> *iter)
	{
		while (iter->hasNext())
		{
			BuildingInfo* b = iter->next();
			cout << *b << endl;
		}

		cout << endl;
	}

private:
	Apart* apart;
	Office* office;
};

 

전체 코드는 다음과 같다.

#include <iostream>
#include <string>
#include <memory>
#include <array>
#include <vector>

using namespace std;

template <typename T>
class Iterator
{
public:
	virtual ~Iterator() = default;
	virtual T* next() = 0;
	virtual bool hasNext() const = 0;
};

/* ---------------- Building Information ------------------ */

class BuildingInfo
{
public:
	BuildingInfo() = default;
	BuildingInfo(int f, string n) : floor(f), name(n) {}
	int getFloor() { return floor; }
	string getName() { return name; }

private:
	int floor;
	string name;
};

ostream& operator<<(ostream& os, BuildingInfo& b)
{
	os << "(" << b.getFloor() << ") [ " << b.getName() << " ]";
	return os;
}

/* -------------------------------------------- */

class ApartIterator : public Iterator<BuildingInfo>
{
public:
	static constexpr size_t MAX_FLOOR = 10;
	ApartIterator(array<BuildingInfo, MAX_FLOOR> &b) : buildingInfo(b) {}
	BuildingInfo* next() override { return &buildingInfo[index++]; }
	bool hasNext() const override { return buildingInfo.size() > index && buildingInfo[index].getName() != ""; }

private:
	array<BuildingInfo, MAX_FLOOR> &buildingInfo;
	array<BuildingInfo, MAX_FLOOR>::size_type index = 0;
};

class Apart
{
public:
	Apart()
	{
		addFloor(1, "blood");
		addFloor(5, "straw");
		addFloor(3, "berry");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		if (floorCount >= MAX_FLOOR) cout << "out of floor!!\n" << endl;
		else floors[floorCount++] = b;
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() { return make_unique<ApartIterator>(floors); }

private:
	static constexpr size_t MAX_FLOOR = 10;
	size_t floorCount = 0;
	array<BuildingInfo, MAX_FLOOR> floors;
};

/* -------------------------------------------- */

class OfficeIterator : public Iterator<BuildingInfo>
{
public:
	OfficeIterator(vector<BuildingInfo> &b) : buildingInfo(b), iter(buildingInfo.begin()) {}
	BuildingInfo* next() override { return &*iter++; }
	bool hasNext() const override { return iter != buildingInfo.end(); }

private:
	vector<BuildingInfo> &buildingInfo;
	vector<BuildingInfo>::iterator iter;
};

class Office
{
public:
	Office()
	{
		addFloor(1, "LG");
		addFloor(5, "NC");
		addFloor(4, "SK");
		addFloor(3, "HYUNDAI");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		floors.push_back(b);
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() { return make_unique<OfficeIterator>(floors); }

private:
	vector<BuildingInfo> floors;
};

/* ----------------- Manager ------------------ */

class Manager
{
public:
	Manager(Apart* apt, Office* ofc) : apart(apt), office(ofc) {}
	void printAll()
	{
		unique_ptr<Iterator<BuildingInfo>> apartIter = apart->makeIterator();
		cout << "Apart Info" << endl;
		printBuildingInfo(apartIter.get());

		unique_ptr<Iterator<BuildingInfo>> officeIter = office->makeIterator();
		cout << "Office Info" << endl;
		printBuildingInfo(officeIter.get());
	}

	void printBuildingInfo(Iterator<BuildingInfo> *iter)
	{
		while (iter->hasNext())
		{
			BuildingInfo* b = iter->next();
			cout << *b << endl;
		}

		cout << endl;
	}

private:
	Apart* apart;
	Office* office;
};

int main(void)
{
	Apart* apart = new Apart();
	Office* office = new Office();

	Manager* manager = new Manager(apart, office);
	manager->printAll();

	cout << "Apart Info" << endl;
	manager->printBuildingInfo(apart->makeIterator().get());

	return 0;
}


Aggregate Interface

 

현재 ManagerApartOffice를 순회하기 위해 아래와 같이 생성자를 만들고 있다.

Manager(Apart* apt, Office* ofc) : apart(apt), office(ofc) {}

 

ApartOffice는 똑같은 메서드를 가지고 있기 때문에 같은 인터페이스를 구현하도록 하자.

 

BuildingInterface 클래스는 makeIterator를 구현하도록 강제한다.

class BuildingInterface
{
public:
	virtual ~BuildingInterface() = default;
	virtual unique_ptr<Iterator<BuildingInfo>> makeIterator() = 0;
};

 

Apart 클래스는 BuildingInterface를 상속하고 makeIterator 옆에 override를 추가하였다.

class Apart : public BuildingInterface
{
public:
	Apart() { ... }
	void addFloor(int f, string n) { ... }
	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<ApartIterator>(floors); }

private:
	...
};

 

ManagerApart, OfficeBulidingInterface로 변경하였다.

class Manager
{
public:
	Manager(BuildingInterface* apt, BuildingInterface* ofc) : apart(apt), office(ofc) {}
    ...
    
private:
	BuildingInterface* apart;
	BuildingInterface* office;
};

 

전체 코드는 다음과 같다.

#include <iostream>
#include <string>
#include <memory>
#include <array>
#include <vector>

using namespace std;

template <typename T>
class Iterator
{
public:
	virtual ~Iterator() = default;
	virtual T* next() = 0;
	virtual bool hasNext() const = 0;
};

/* ---------------- Building Information ------------------ */

class BuildingInfo
{
public:
	BuildingInfo() = default;
	BuildingInfo(int f, string n) : floor(f), name(n) {}
	int getFloor() { return floor; }
	string getName() { return name; }

private:
	int floor;
	string name;
};

class BuildingInterface
{
public:
	virtual ~BuildingInterface() = default;
	virtual unique_ptr<Iterator<BuildingInfo>> makeIterator() = 0;
};

ostream& operator<<(ostream& os, BuildingInfo& b)
{
	os << "(" << b.getFloor() << ") [ " << b.getName() << " ]";
	return os;
}

/* -------------------------------------------- */

class ApartIterator : public Iterator<BuildingInfo>
{
public:
	static constexpr size_t MAX_FLOOR = 10;
	ApartIterator(array<BuildingInfo, MAX_FLOOR> &b) : buildingInfo(b) {}
	BuildingInfo* next() override { return &buildingInfo[index++]; }
	bool hasNext() const override { return buildingInfo.size() > index && buildingInfo[index].getName() != ""; }

private:
	array<BuildingInfo, MAX_FLOOR> &buildingInfo;
	array<BuildingInfo, MAX_FLOOR>::size_type index = 0;
};

class Apart : public BuildingInterface
{
public:
	Apart()
	{
		addFloor(1, "blood");
		addFloor(5, "straw");
		addFloor(3, "berry");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		if (floorCount >= MAX_FLOOR) cout << "out of floor!!\n" << endl;
		else floors[floorCount++] = b;
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<ApartIterator>(floors); }

private:
	static constexpr size_t MAX_FLOOR = 10;
	size_t floorCount = 0;
	array<BuildingInfo, MAX_FLOOR> floors;
};

/* -------------------------------------------- */

class OfficeIterator : public Iterator<BuildingInfo>
{
public:
	OfficeIterator(vector<BuildingInfo> &b) : buildingInfo(b), iter(buildingInfo.begin()) {}
	BuildingInfo* next() override { return &*iter++; }
	bool hasNext() const override { return iter != buildingInfo.end(); }

private:
	vector<BuildingInfo> &buildingInfo;
	vector<BuildingInfo>::iterator iter;
};

class Office : public BuildingInterface
{
public:
	Office()
	{
		addFloor(1, "LG");
		addFloor(5, "NC");
		addFloor(4, "SK");
		addFloor(3, "HYUNDAI");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		floors.push_back(b);
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<OfficeIterator>(floors); }

private:
	vector<BuildingInfo> floors;
};

/* ----------------- Manager ------------------ */

class Manager
{
public:
	Manager(BuildingInterface* apt, BuildingInterface* ofc) : apart(apt), office(ofc) {}
	void printAll()
	{
		unique_ptr<Iterator<BuildingInfo>> apartIter = apart->makeIterator();
		cout << "Apart Info" << endl;
		printBuildingInfo(apartIter.get());

		unique_ptr<Iterator<BuildingInfo>> officeIter = office->makeIterator();
		cout << "Office Info" << endl;
		printBuildingInfo(officeIter.get());
	}

	void printBuildingInfo(Iterator<BuildingInfo> *iter)
	{
		while (iter->hasNext())
		{
			BuildingInfo* b = iter->next();
			cout << *b << endl;
		}

		cout << endl;
	}

private:
	BuildingInterface* apart;
	BuildingInterface* office;
};

int main(void)
{
	Apart* apart = new Apart();
	Office* office = new Office();

	Manager* manager = new Manager(apart, office);
	manager->printAll();

	cout << "Apart Info" << endl;
	manager->printBuildingInfo(apart->makeIterator().get());

	return 0;
}

 

ConcreteAggregateConcreteIterator의 인스턴스를 만들어야 하기 때문에 아래의 클래스 다이어그램이 나온다.


map으로 만들어진 상가 건물

 

이제 map으로 구성된 Store 클래스를 추가해 보자.

class StoreIterator : public Iterator<BuildingInfo>
{
public:
	StoreIterator(map<int, BuildingInfo> &b) : buildingInfo(b), iter(buildingInfo.begin()) {}
	BuildingInfo* next() override { return &iter++->second; }
	bool hasNext() const override { return iter != buildingInfo.end(); }

private:
	map<int, BuildingInfo> &buildingInfo;
	map<int, BuildingInfo>::iterator iter;
};

class Store : public BuildingInterface
{
public:
	Store()
	{
		addFloor(7, "steak");
		addFloor(3, "chicken");
		addFloor(1, "fork");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		floors[order++] = b; // 입주한 순서대로 BuildingInfo를 저장하는 Store
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<StoreIterator>(floors); }

private:
	int order = 0;
	map<int, BuildingInfo> floors;
};

 

클라이언트 코드Store를 추가하였기 때문에 다음과 같이 변경된다.

int main(void)
{
	Apart* apart = new Apart();
	Office* office = new Office();
	Store* store = new Store();

	Manager* manager = new Manager(apart, office, store);
	manager->printAll();

	return 0;
}

 

그러나 현재 건물주(Manager)는 Store 클래스가 추가되면서 내부 코드를 수정해야 한다.

class Manager
{
public:
	Manager(BuildingInterface* apt, BuildingInterface* ofc, BuildingInterface* sto) : apart(apt), office(ofc), store(sto) {}
	void printAll()
	{
		...
        
		unique_ptr<Iterator<BuildingInfo>> storeIter = store->makeIterator();
		cout << "Store Info" << endl;
		printBuildingInfo(storeIter.get());
	}

	void printBuildingInfo(Iterator<BuildingInfo> *iter) { ... }
		
private:
	BuildingInterface* apart;
	BuildingInterface* office;
	BuildingInterface* store;
};

 

이 코드는 map<string BuildingType, BuildingInterface>을 이용해서 개선할 수 있다.

Manager를 다음과 같이 수정한다. 

class Manager
{
public:
	Manager(map<string, unique_ptr<BuildingInterface>>& b) : buildings(b) {}
	void printAll()
	{	
		for (const auto& pair : buildings)
		{
			string buildingType = pair.first;
			const unique_ptr<BuildingInterface>& bi = pair.second;
			unique_ptr<Iterator<BuildingInfo>> iter = bi->makeIterator();

			cout << pair.first << endl;
			printBuildingInfo(iter.get());
		}
	}

	void printBuildingInfo(Iterator<BuildingInfo> *iter)
	{
		while (iter->hasNext())
		{
			BuildingInfo* b = iter->next();
			cout << *b << endl;
		}

		cout << endl;
	}

private:
	map<string, unique_ptr<BuildingInterface>>& buildings;
};

 

이제 클라이언트에 새로운 건물이 추가되어도 Manager의 코드를 변경할 필요가 없다.

int main(void)
{	
	map<string, unique_ptr<BuildingInterface>> buildings;

	buildings["APART"] = make_unique<Apart>();
	buildings["OFFICE"] = make_unique<Office>();
	buildings["STORE"] = make_unique<Store>();

	Manager* manager = new Manager(buildings);
	
	manager->printAll();

	return 0;
}

 

전체 코드는 다음과 같다.

#include <iostream>
#include <string>
#include <memory>
#include <array>
#include <vector>
#include <map>

using namespace std;

template <typename T>
class Iterator
{
public:
	virtual ~Iterator() = default;
	virtual T* next() = 0;
	virtual bool hasNext() const = 0;
};

/* ---------------- Building Information ------------------ */

class BuildingInfo
{
public:
	BuildingInfo() = default;
	BuildingInfo(int f, string n) : floor(f), name(n) {}
	int getFloor() { return floor; }
	string getName() { return name; }

private:
	int floor;
	string name;
};

class BuildingInterface
{
public:
	virtual ~BuildingInterface() = default;
	virtual unique_ptr<Iterator<BuildingInfo>> makeIterator() = 0;
};

ostream& operator<<(ostream& os, BuildingInfo& b)
{
	os << "(" << b.getFloor() << ") [ " << b.getName() << " ]";
	return os;
}

/* -------------------------------------------- */

class ApartIterator : public Iterator<BuildingInfo>
{
public:
	static constexpr size_t MAX_FLOOR = 10;
	ApartIterator(array<BuildingInfo, MAX_FLOOR> &b) : buildingInfo(b) {}
	BuildingInfo* next() override { return &buildingInfo[index++]; }
	bool hasNext() const override { return buildingInfo.size() > index && buildingInfo[index].getName() != ""; }

private:
	array<BuildingInfo, MAX_FLOOR> &buildingInfo;
	array<BuildingInfo, MAX_FLOOR>::size_type index = 0;
};

class Apart : public BuildingInterface
{
public:
	Apart()
	{
		addFloor(1, "blood");
		addFloor(5, "straw");
		addFloor(3, "berry");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		if (floorCount >= MAX_FLOOR) cout << "out of floor!!\n" << endl;
		else floors[floorCount++] = b;
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<ApartIterator>(floors); }

private:
	static constexpr size_t MAX_FLOOR = 10;
	size_t floorCount = 0;
	array<BuildingInfo, MAX_FLOOR> floors;
};

/* -------------------------------------------- */

class OfficeIterator : public Iterator<BuildingInfo>
{
public:
	OfficeIterator(vector<BuildingInfo> &b) : buildingInfo(b), iter(buildingInfo.begin()) {}
	BuildingInfo* next() override { return &*iter++; }
	bool hasNext() const override { return iter != buildingInfo.end(); }

private:
	vector<BuildingInfo> &buildingInfo;
	vector<BuildingInfo>::iterator iter;
};

class Office : public BuildingInterface
{
public:
	Office()
	{
		addFloor(1, "LG");
		addFloor(5, "NC");
		addFloor(4, "SK");
		addFloor(3, "HYUNDAI");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		floors.push_back(b);
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<OfficeIterator>(floors); }

private:
	vector<BuildingInfo> floors;
};

/* -------------------------------------------- */

class StoreIterator : public Iterator<BuildingInfo>
{
public:
	StoreIterator(map<int, BuildingInfo> &b) : buildingInfo(b), iter(buildingInfo.begin()) {}
	BuildingInfo* next() override { return &iter++->second; }
	bool hasNext() const override { return iter != buildingInfo.end(); }

private:
	map<int, BuildingInfo> &buildingInfo;
	map<int, BuildingInfo>::iterator iter;
};

class Store : public BuildingInterface
{
public:
	Store()
	{
		addFloor(7, "steak");
		addFloor(3, "chicken");
		addFloor(1, "fork");
	}

	void addFloor(int f, string n)
	{
		BuildingInfo b = BuildingInfo(f, n);
		floors[order++] = b; // 입주한 순서대로 BuildingInfo를 저장하는 Store
	}

	unique_ptr<Iterator<BuildingInfo>> makeIterator() override { return make_unique<StoreIterator>(floors); }

private:
	int order = 0;
	map<int, BuildingInfo> floors;
};

/* ----------------- Manager ------------------ */

class Manager
{
public:
	Manager(map<string, unique_ptr<BuildingInterface>>& b) : buildings(b) {}
	void printAll()
	{	
		for (const auto& pair : buildings)
		{
			string buildingType = pair.first;
			const unique_ptr<BuildingInterface>& bi = pair.second;
			unique_ptr<Iterator<BuildingInfo>> iter = bi->makeIterator();

			cout << pair.first << endl;
			printBuildingInfo(iter.get());
		}
	}

	void printBuildingInfo(Iterator<BuildingInfo> *iter)
	{
		while (iter->hasNext())
		{
			BuildingInfo* b = iter->next();
			cout << *b << endl;
		}

		cout << endl;
	}

private:
	map<string, unique_ptr<BuildingInterface>>& buildings;
};

int main(void)
{	
	map<string, unique_ptr<BuildingInterface>> buildings;

	buildings["APART"] = make_unique<Apart>();
	buildings["OFFICE"] = make_unique<Office>();
	buildings["STORE"] = make_unique<Store>();

	Manager* manager = new Manager(buildings);
	
	manager->printAll();

	return 0;
}

ClassDiagram.md

```mermaid
  classDiagram    
    class Iterator { 
      hasNext()*
      next()*
    }
    class ApartIterator { 
      hasNext()
      next()
    }
    class OfficeIterator { 
      hasNext()
      next()
    }
    class Manager {
      printAll()
    }
    class Building {
      makeIterator()*
    }
    class Apart {
      floors
      makeIterator()
    }
    class Office {
      floors
      makeIterator()
    }
    
    <<Interface>> Iterator
    <<Interface>> Building
    

    Iterator <|.. ApartIterator
    Iterator <|.. OfficeIterator    
    Iterator <-- Manager
    Building <-- Manager
    Building <|.. Apart
    Building <|.. Office    
```
반응형

댓글