이미 개체간에 어떤 종류의 관계가 있다고 판단한 것 같습니다. 하지만, 당신은 막연하게 관계를 묘사합니다.
RegisterALL
이 단순 봉쇄를 사용하는 경우 매우 간단한 관계가됩니다. 이 관계는 다음과 같이 표현 될 수 있습니다 (ASCII 그래픽을 사용하십시오) :
+-------------+
| RegisterALL | --> := has
+-------------+
| |
v v
+-----------+ +-----------+
| ARegister | | BRegister |
+-----------+ +-----------+
이점은 두 부양 가족에 대한 그림이 매우 간단하다는 것입니다. 그러나 많은 개체를 등록하는 경우 그림은 XRegister
개체의 무리로 폭발하는 RegisterALL
처럼 보이기 시작합니다.
RegisterALL
경우는 ARegister
및 BRegister
, 당신은 RegisterALL
컨테이너를 유지 할 수 있도록 ARegister
및 BRegister
위한 공통 기본 클래스를 생성 할 수 있습니다 포함하기위한 것입니다.
+-------------+ +------------------+ <>--> := aggregates
| RegisterALL |<>--->| AbstractRegister |
+-------------+ +------------------+ |
| _/_\_ := inherits
/\
___/___\___
| |
+-----------+ +-----------+
| ARegister | | BRegister |
+-----------+ +-----------+
우리는 많은 새로운 항목이 등록되는 방법을 상관없이, RegisterALL
와 AbstractRegister
사이의 관계는 동일하게 유지 것을 알 수있다. 한발 더 나아가 템플릿에서 ARegister
과 BRegister
을 유도 할 수 있습니다.
+-------------+ +------------------+
| RegisterALL |<>--->| AbstractRegister |
+-------------+ +------------------+
|
/\
/___\
|
| +--------------+
+--------------| RegisterType |
| +--------------+
| RegisterTemplate |
+------------------+
좋아, 너무 많은 OO 디자인 수업. 이것은 코드로 변환됩니다. 쉬운 일부터 시작합시다. RegisterType
은 등록 할 여러 항목을 열거합니다. RegisterTypeName
과 오버로드 된 연산자를 사용하면 RegisterType
을 인쇄 할 때 코드가 숫자 대신 문자열을 인쇄 할 수 있습니다.
enum RegisterType { A, B, MAX_RegisterType };
static inline std::string
RegisterTypeName (RegisterType t)
{
static const char * names[] = { "A", "B" };
return names[t];
}
static inline std::ostream &
operator << (std::ostream &output, RegisterType t)
{
return output << RegisterTypeName(t);
}
AbstractRegister
은이 유형을 쿼리하는 인터페이스를 제공합니다. 또한 poke
인터페이스에는 기본 구현이 제공됩니다. C++에서 추상 형식은 가상 소멸자를 제공해야합니다.
class AbstractRegister {
public:
virtual ~AbstractRegister() {}
virtual RegisterType type() const = 0;
virtual void poke() { std::cout << "Poked " << type(); }
};
typedef std::unique_ptr<AbstractRegister> AbstractRegisterPtr;
static const AbstractRegisterPtr AbstractRegisterNullPtr;
RegisterALL
클래스 형 AbstractRegister
의 물건을 보유하는 용기가있다. 지도를 사용하여 AbstractRegister
인스턴스에 RegisterType
인스턴스를 연결합니다.이 인스턴스는 등록하려고합니다. RegisterALL
은 하나의 인스턴스 만 허용한다는 의미에서 싱글 톤으로 구현됩니다. add
메서드는 등록을 수행하고 find
메서드를 사용하면 등록 된 인스턴스를 찾을 수 있습니다. 의 정의가 끝날 때까지 RegisterALL
생성자의 구현이 연기됩니다.
class RegisterALL {
template <RegisterType> friend class RegisterTemplate;
typedef std::unique_ptr<RegisterALL> SelfPtr;
typedef std::map<RegisterType, AbstractRegisterPtr> RegisterMap;
void add (AbstractRegister *r) { all[r->type()] = AbstractRegisterPtr(r); }
RegisterALL();
public:
static const SelfPtr & instance() {
if (!one) new RegisterALL;
return one;
}
const AbstractRegisterPtr & find (RegisterType t) const {
RegisterMap::const_iterator i = all.find(t);
return (i != all.end()) ? i->second : AbstractRegisterNullPtr;
}
private:
static SelfPtr one;
RegisterMap all;
};
RegisterALL::SelfPtr RegisterALL::one;
RegisterTemplate
클래스 AbstractRegister
에서 유래하고 RegisterType
의해 파라미터 화된다. 템플릿 매개 변수의 값을 반환하여 type
가상 메서드를 구현합니다. 또한 싱글 톤을 사용하지만 인스턴스를 공개하지는 않습니다. 대신 인스턴스는 RegisterALL
으로 관리됩니다. 그것은 자신을 RegisterALL
으로 등록하는 register_type
메소드를 제공하며이 인스턴스는 RegisterALL
에있는 find
메소드를 사용해야 만 찾을 수 있습니다.
template <RegisterType RT>
class RegisterTemplate : public AbstractRegister {
RegisterType type() const { return RT; }
void poke() {
std::cout << "Poked " << RegisterTypeName(RT) << std::endl;
}
RegisterTemplate() {
std::cout << "Created " << RegisterTypeName(RT) << std::endl;
}
~RegisterTemplate() {
std::cout << "Destroying " << RegisterTypeName(RT) << std::endl;
}
public:
static void register_type() {
if (RegisterALL::instance()->find(RT)) {
std::cout << "Already registered " << RegisterTypeName(RT)
<< std::endl;
return;
}
RegisterALL::instance()->add(new RegisterTemplate<RT>);
}
};
RegisterALL
생성자 헬퍼 register_all
템플릿을 이용하는 것을 RegisterType
ENUM를 반복하고, 이에 모든 RegisterType
년대 RegisterALL
가 등록되게 해당 RegisterTemplate
인스턴스화.
그래서
template <unsigned X>
struct register_all {
register_all() {
RegisterTemplate<static_cast<RegisterType>(X)>::register_type();
register_all<X+1>();
}
};
template <> struct register_all<MAX_RegisterType> {};
inline RegisterALL::RegisterALL()
{
one = std::move(SelfPtr(this));
register_all<0>();
}
그것을 밖으로 시도, 우리는 다음 코드를 사용합니다
RegisterALL::instance(); // registers all RegisterType's
RegisterTemplate<B>::register_type(); // try to register B again
RegisterALL::instance()->find(A)->poke(); // poke at A
을 그리고 이것은 출력 :
Created A
Created B
Already registered B
Poked A
Destroying B
Destroying A
공지 사항 스마트 포인터가 자동으로 등록 된 항목을 정리하는 방법 우리를 위해.
돌아가서 대답을 수락 해주십시오. 이것은 사람들이 당신을 도우라고 권합니다. – Hassan
"프로젝트에서 예외를 사용하지 않습니다." 이것에 대한 좋은 이유가 있습니까? 모든 예외를 비활성화 하시겠습니까? (예 :'new'가 실패하면 throw합니까?)'NULL'을 반환합니까?'new '를 사용하지 않습니까?) –
예, 우리는 "new"를 사용합니다. "new"로 객체를 초기화 한 후 NULL을 확인합니다. – Saaras