2010-04-09 3 views
4

나는 어려움을 겪고있는 문제에 대해 질문이 있습니다. 당신이 나와 함께 견딜 수 있기를 바랍니다.디자인에 관한 질문 (상속, 다형성)

상상해 보겠습니다. 실제 객체의 계층 구조의 기본 클래스를 나타내는 Object 클래스가 있다고 가정 해보십시오. 나중에 그것으로부터 상속 받아 Object1D, Object2D 및 Object3D 클래스를 만듭니다. 이러한 파생 클래스 각각에는 몇 가지 특정 메서드와 특성이 있습니다. 예를 들어, 3d 객체는 렌더러가 사용할 3D 모델을 다운로드하는 기능을 가질 수 있습니다. 이 유사한에서 :-) 를 렌더링,

class Object {}; 
class Object1D : public Object { Point mPos; }; 
class Object2D : public Object { ... }; 
class Object3D : public Object { Model mModel; }; 

이제 단순히 아니라 인수로 객체를 받아 렌더러라는 별도의 클래스를 가질 것 :

그래서 나는이 같은이있을 것이다 그런데 여러 종류의 렌더러를 지원하고 싶습니다. 예를 들어, 나는 모든 객체는 객체의 어떤 종류의 다른 특정 렌더러에 의존하고 제공 할 수있는 기본 일 수 :

class Renderer {}; // Default one 
class Renderer3D : public Renderer {}; 

을 그리고 여기 내 문제는 온다. 렌더러 클래스는 Object를 인수로 가져와야합니다. 예를 들어 생성자에서 객체를 렌더링하는 데 필요한 데이터를 가져와야합니다.

지금까지 그렇게 좋았습니다. 그러나 Renderer3D는 기본 속성뿐만 아니라 3D 객체의 특정 속성을 얻기 위해 Object3D 인수를 가져와야합니다.

생성자는 다음과 같이 보일 것이다 :

이제
CRenderer(Object& object); 
CRenderer3D(Object3D& object); 

어떻게 일반적인 방법이 지정합니까? 아니면 더 나은 방법은 이것을 디자인하는 것입니까?

나는 RTTI 나 비슷한 것에 의지 할 수 있다는 것을 알고 있지만 가능한 한 이것을 피하고 싶습니다. 아마도 이것을 해결할 더 좋은 방법이있을 것입니다. 사전에

감사합니다!

+0

도움을 주셔서 감사합니다. 정말 감사 드리며 지난 몇 시간을 다시 생각해 보았습니다. 각 답변마다 내 의견을 보아주십시오. – Dan

+0

"Object"와 다른 이름을 사용하고자 할 수 있습니다. –

답변

3

한 가지 방법은 getRenderer() 메소드가 반환 불구하고 객체가 자신의 렌더러의를 만들 수 있도록하는 것입니다 적절한 형태의 렌더러 이것은 Factory Method 패턴의 예입니다. 구현 언어의 기능에 따라 getRenderer 메소드는 부모 Renderer 클래스/인터페이스의 인스턴스를 반환하여 부모 Render 클래스의 추상 메소드가 될 수 있습니다. 특정 Renderers가 확장/구현합니다.

4

이 커플 링을 처리하는 한 가지 방법은 공장을 사용하는 것입니다. 일반 팩토리는 객체와 렌더러를 만듭니다. 2D 팩토리는 2D 객체 및 호환 가능한 2D 렌더러를 만들고 3D 팩토리는 3D 객체 및 호환 3D 렌더러를 만듭니다.

abstract class Factory { 
    abstract Object createObject(); 
    abstract Renderer createRenderer(); 
} 

class 2DFactory { 
    Object createObject() { return new 2DObject(); } 
    Renderer createRenderer() { return new 2DRenderer(); } 
} 

// similarly for 3D 

class Client { 
    Client(Factory factory) { ... } 
    void render() { 
    factory.createRenderer().render(factory.createObject()); 
    } 
} 

따라서 다른 팩토리의 제품을 혼합하지 않으면 클라이언트 코드를 깨끗하게 유지할 수 있습니다. 클라이언트 코드가 한 번에 하나의 렌더러 객체 & 렌더러 만 처리하는 경우 적절한 팩토리를 전달한 다음 해당 콘크리트 유형을 모른 채 객체와 렌더러를 사용하게하는 것이 쉽습니다. 이것에 대한 변형은 객체가 팩토리 메서드를 통해 호환 렌더러를 만들도록하는 것입니다 (suggested by Jason).

또 다른 가능성은 템플릿/제네릭을 사용하는 것일 수 있지만 언어마다 다릅니다. 당신의 구현 언어는 C++과 비슷해 보입니다. 그래서 저는이 방향으로 나아갑니다. 템플릿 전문화를 사용할 수 있습니다.

template<class T> class Renderer { 
    void render(T object) { ... } 
}; 

template<> class Renderer<Object3D> { 
    void render(Object3D object) { 
    // render the 3D way 
    } 
}; 

// similarly for 2D 
1

이 작업은 가능합니까?

1

이중 발송 패턴을 찾는 것처럼 들립니다.이를 사용하려면 다음과 같이 귀하의 기본 클래스에 뭔가를 추상 메소드를 추가

Object2D.Dispatch(renderer) 
{ 
    renderer.Render2D(self) 
} 
: 개체의 각 서브 클래스는 다음의 유형에 대한 제공 렌더러에 적절한 방법을 파견을 무시하고 호출
Dispatch(renderer) 

인터페이스를 사용하여 더 일반적인 인터페이스로 만들 수도 있습니다. 각 개체 유형 렌더링을위한 인터페이스를 작성하고 발송 방법 체크를해야 올바른 인터페이스를 지원하는 경우 :

Object2D.Dispatch(renderer) 
{ 
    render2d = render as IRender2D 
    if render2d found 
     render2d.Render(self) 
} 
+0

그래,이 경우 각 렌더러는 다른 기능을 가질 것이다. 나는 일반적인 기본 클래스를 사용할 수 없지만 다른 방법으로 보이지 않는다. – Dan

0

여기를 살펴 보는 또 다른 방법이 있습니다. 렌더러를 객체의 일부로 만듭니다. 생성하는 각 객체에 적절한 렌더러를 할당하고

Render(){ 
    myRenderer.Render(this) 
}