문제

내가 알고 있는 상속 다이아몬드가 나쁜 것으로 간주습니다.그러나 저는 2 는 경우에는 다이아몬드 상속할 수 없습합니다.제가 물어보고 싶은 것이 좋습니다 나를 사용하는 다이아몬드 상속에서는 이러한 경우,또는 다른 디자인이 더 좋을 수 있습니다.

Case1: 을 만들고 싶을 나타내는 클래스가 다른 종류의"동작에서"나는 시스템.작업으로 분류된 여러 매개변수:

  • 작업이 될 수 있습니다"읽기"또는"쓰기".
  • 작업할 수 있으로 지연 또는 지체없이(그것은 단지 1 매개 변수입니다.그것을 변경하는 행동을 크게).
  • 작업의"유형"수 있습 FlowA 또는 FlowB.

내가 하려는 다음과 같은 디자인:

// abstract classes
class Action  
{
    // methods relevant for all actions
};
class ActionRead      : public virtual Action  
{
    // methods related to reading
};
class ActionWrite     : public virtual Action  
{
    // methods related to writing
};
class ActionWithDelay : public virtual Action  
{
    // methods related to delay definition and handling
};
class ActionNoDelay   : public virtual Action  {/*...*/};
class ActionFlowA     : public virtual Action  {/*...*/};
class ActionFlowB     : public virtual Action  {/*...*/};

// concrete classes
class ActionFlowAReadWithDelay  : public ActionFlowA, public ActionRead, public ActionWithDelay  
{
    // implementation of the full flow of a read command with delay that does Flow A.
};
class ActionFlowBReadWithDelay  : public ActionFlowB, public ActionRead, public ActionWithDelay  {/*...*/};
//...

물론,순종하는 없음 2 작업(에서 상속하는 액션스 클래스)를 구현하는 것이 동일한 방법입니다.

사례 2: 나를 구현하는 복합 위한 디자인 패턴을"명령"제 시스템이다.명령될 수 있는 읽기,쓰기,삭제,등등.나는 또한 시퀀스의 명령할 수도 있는 읽기,쓰기,삭제,등등.시퀀스의 명령을 포함할 수 있는 다른 시퀀스의 명령입니다.

그래서 나는 다음과 같은 디자인:

class CommandAbstraction
{
    CommandAbstraction(){};
    ~CommandAbstraction()=0;
    void Read()=0;
    void Write()=0;
    void Restore()=0;
    bool IsWritten() {/*implemented*/};
    // and other implemented functions
};

class OneCommand : public virtual CommandAbstraction
{
    // implement Read, Write, Restore
};

class CompositeCommand : public virtual CommandAbstraction
{
    // implement Read, Write, Restore
};

또한,특별한 종류의 명령,"현대"명령입니다.모두 하나의 명령하고 복합 명령할 수 있는 현대가 될 것입니다.는"현대적인"추가 특정한 목록의 특성을 하나의 명령하고 복합 명령(대부분 동일한 모두에 대한 속성을 그들의).고 싶을 보유 할 수있는 포인터를 CommandAbstraction,그리고 초기화(통해 새로운)에 따라 필요한 형식의 명령입니다.그래서 나는 다음을 수행하려는 디자인의 외에도(위):

class ModernCommand : public virtual CommandAbstraction
{
    ~ModernCommand()=0;
    void SetModernPropertyA(){/*...*/}
    void ExecModernSomething(){/*...*/}
    void ModernSomethingElse()=0;

};
class OneModernCommand : public OneCommand, public ModernCommand
{
    void ModernSomethingElse() {/*...*/};
    // ... few methods specific for OneModernCommand
};
class CompositeModernCommand : public CompositeCommand, public ModernCommand
{
    void ModernSomethingElse() {/*...*/};
    // ... few methods specific for CompositeModernCommand
};

다시 나을 것이 없는지 확인 2 클래스를 상속받 CommandAbstraction 클래스를 구현하는 것이 동일한 방법입니다.

감사합니다.

도움이 되었습니까?

해결책

상속가 두 번째 가장 강한(더 많은 커플링)의 관계에서는 C++,선행에 의해서만 우정이다.할 수 있는 경우 재 사용으로만 구성하는 코드는 것이 더 느슨하게 결합합니다.할 수 없는 경우,다음을 고려해야하는지 여부 모든 클래스에 정말 상속에서 기지이다.그것은으로 인해 구현 또는 인터페이스?당신이 원하는 것을 사용하여 어떤 요소 계층구조에 기초로를 받으려면 어떻게 해야 합니까?나는 나뭇잎에서 당신의 계층 구조는 실제 행동니까?는 경우에만 나뭇잎은 작업과 추가하는 동작을 고려할 수 있는 정책 기반의 디자인에 대한 이 유형의 조성물의 행동을 합니다.

아이디어는 다른(직교)행위에서 정의할 수 있는 작은 클래스 세트와 그 함께 번들로 제공 실시 완전한 행동입니다.예에서 나는 것을 고려해 하나의 정책지 여부를 정의하는 작업이 실행되는 현재 또는 미래,그리고 이 명령을 실행합니다.

제공하는 추상 클래스가 다른 인스턴스화의 템플릿 저장할 수 있습니다(포인터를 통해)컨테이너 또는 전달하는 기능으로 인수와라 다형적으로.

class ActionDelayPolicy_NoWait;

class ActionBase // Only needed if you want to use polymorphically different actions
{
public:
    virtual ~Action() {}
    virtual void run() = 0;
};

template < typename Command, typename DelayPolicy = ActionDelayPolicy_NoWait >
class Action : public DelayPolicy, public Command
{
public:
   virtual run() {
      DelayPolicy::wait(); // inherit wait from DelayPolicy
      Command::execute();  // inherit command to execute
   }
};

// Real executed code can be written once (for each action to execute)
class CommandSalute
{
public:
   void execute() { std::cout << "Hi!" << std::endl; }
};

class CommandSmile
{
public:
   void execute() { std::cout << ":)" << std::endl; }
};

// And waiting behaviors can be defined separatedly:
class ActionDelayPolicy_NoWait
{
public:
   void wait() const {}
};

// Note that as Action inherits from the policy, the public methods (if required)
// will be publicly available at the place of instantiation
class ActionDelayPolicy_WaitSeconds
{
public:
   ActionDelayPolicy_WaitSeconds() : seconds_( 0 ) {}
   void wait() const { sleep( seconds_ ); }
   void wait_period( int seconds ) { seconds_ = seconds; }
   int wait_period() const { return seconds_; }
private:
   int seconds_;
};

// Polimorphically execute the action
void execute_action( Action& action )
{
   action.run();
}

// Now the usage:
int main()
{
   Action< CommandSalute > salute_now;
   execute_action( salute_now );

   Action< CommandSmile, ActionDelayPolicy_WaitSeconds > smile_later;
   smile_later.wait_period( 100 ); // Accessible from the wait policy through inheritance
   execute_action( smile_later );
}

이용 상속의 공공할 수 있습 방법에서 정책을 구현을 통해 액세스할 수 있습니다 템플릿에 인스턴스화.이 허용하지 않 사용하는 응집의 결합에 대한 정책으로 더 새로운 기능 구성원이 될 수 있으로 밀려준 인터페이스입니다.이 예에서는 템플릿 정책에 따라 데 wait()메소드는 모든 일반적인을 기다리고 정책입니다.지금 기다리고 있는 기간에 대한 필요가 고정된 기간 동안 설정된 시간 기간을 통해()공공의 방법입니다.

예제에서,NoWait 정책은 특정의 예 WaitSeconds 정책과 기간을 0 으로 설정됩니다.이 의도적으로 표시하는 정책 인터페이스에 필요하지 않은 것 같습니다.다른 기다리고 정책을 구현할 수 있에 기다리고 있을 수의 밀리초,시계,또는 일부를 외부여 이벤트를 제공하는 클래스 레지스터 콜백으로 지정된 이벤트이다.

지 않는 경우에 필요한 다형성을 수 있는 예제에서 기본 클래스고 가상의 방법이 모두 있습니다.이 지나치게 복잡한 현재 예를 결정할 수 있습니다 추가에는 다른 정책을 혼합합니다.

를 추가하는 동안 새로운 직각 행동을 의미하는 것 기하급수적으로 증서 번호를 클래스의 경우 일반 상속 사용(다형성)이 접근할 수 있습니다 그냥 구현하는 각각의 다른 부분을 따로따로 접착제에서 함께 작업 템플릿입니다.

예를 들어,당신은 당신을 만들 수 있는 활동 주기적으로 추가구사항을 결정하는 경우를 종료하려면 정기적인 반복입니다.첫 번째 옵션은 마음에 올 LoopPolicy_NRuns 및 LoopPolicy_TimeSpan,LoopPolicy_Until.이 정책의 방법(exit()나 케이스)이라고 한 번에 대한 각 loop.첫 번째 구현을 계산하는 횟수가 호출되는 종료 후에 번호(고정된 사용자에 의해,기간으로 수정되었 위의 예에서).두 번째 구현 정기적으로 실행하는 프로세스에 대한된 시간 기간 동안 마지막 중 하나는 것이 실행될 때까지 이 프로세스 주어진 시간(시간).

는 경우 다음과 같은 여전히 나를 여기에,내가 참으로 일부 내용이 변경되었습니다.첫 번째 하나는 대신 템플릿을 사용하여 매개 변수 명령을 구현하는 방법 execute()내가 사용하는 것이 함수와 템플릿 생성자는 명령을 실행하기로 매개 변수입니다.근거는 이것은 훨씬 더 많은 확장성과 조합 라이브러리로 부스트::결합하거나 부스트::람다,이후에는 경우는 명령을 수밖에 없는 지점에서의 인스턴스를 어떤 기능,함수,또는 회원의 방법은 클래스입니다.

지금 내가 가야하지만,관심이 있는 경우 시도 할 수시로 수정 버전입니다.

다른 팁

거기 디자인-품질 차이를 구현을 지향적 다이아몬드 상속가 구현 상속(위험),와 동등 지향 상속 인터페이스 또는 마커를 이용한 인터페이스를 상속(자주 유용합니다).

일반적으로는 경우에,당신은 피할 수 있습니다 전에,당신은 나 때문에 어딘가에 선 정확한 호출되는 방법에 문제가 발생할 수 있습하고,중요성의 가상 기지국,etc., 시작 중요 xx 웅요.사실,Java 할 수 있도록 허락하지 않았죠 당신을 위해 무언가는,그것만 지원 인터페이스는 계층 구조로 구성됩니다.

내가 생각하는"가장 깨끗한"디자인이 올 수 있습니다 이를 효과적으로 차례의 모든 클래스에는 다이아몬드로의 모형 인터페이스(에 의해이없는 상태 정보,그리고 순수한 가상의 방법).이 영향은 줄어들의 모호성.그리고 물론,여러 개를 사용할 수 있습니다 심지어 다이아몬드 상속 이처럼 당신이 사용하는 것을 구현에서 Java.

그런 다음,설정된 콘크리트의 구현을의 이러한 인터페이스를 구현할 수 있는 다른 방법으로(E.g., 집계,심지어 상속 등)을 실시하고 있습니다.

캡슐화하는 이 프레임워크에서는 외부의 고객을 얻을 인터페이스와 절대와 직접 구체적인 유형을 확인하여 철저하게 테스트를 구현합니다..

물론,이것은 많은 일,그러나 만약 당신이 작성 중고 재사용할 수 있는 API,이것은 당신의 최선의 방법입니다.

내가 달렸으로 이 문제는 단지 이번 주 문제가하는 설명 및 문제 때 당신은하지 말아야에 대해 우려하다.그것은 여기:

"여러 상속 유용한 것으로 간주됩"

"다이아몬드"상속 계층 구조에서의 인터페이스는 매우 안전하다-그것은 상속의 코드는 당신이 뜨거운 물.

코드 재사용,내가 조언을 고려될 것입니다(구글에 대한 C++믹스인 익숙하지 않은 경우에 tequnique).을 사용할 때될 것입니다처럼 당신은 느낄 수 있다"쇼핑"코드를 조각하는 당신을 구현해야 당신은 클래스를 사용하지 않고 여러 상속의 상태 저장됩니다.

그래서,패턴이-여러 상속의 인터페이스 및 하나의 체인의 믹스인(을 주는 코드가 다시 사용)을 구현하는 데 도움이됩 콘크리트 클래스입니다.

도움이 됐으면 좋겠어!

과 함께 첫 번째 예제.....

그는지 여부를 ActionRead ActionWrite 해야 하위 클래스의 작업에 모두.

기 때문에 당신은 끝날 것으로 한 콘크리트 클래스는 작업이 될 것입 어쨌든,당신은 수만 상속 actionread 및 actionwrite 그들이 없는 행동합니다.

하지만,당신을 발명하는 코드를 필요로 그들을 이 작업입니다.그러나 일반적으로 하려고와 별도의 액션,읽기,쓰기,지연 그리고 그냥 콘크리트 클래스 호텔 모두는 함께

아웃과 함께 더 알고 무엇을 하 고, 나는 가능하게 재구성하는 것은 비트입니다.대신 여러 inheritence 모든 이전 버전의 액션, 을 다형 읽기와 쓰기와 쓰기를 클래스 instanciated 같습니다.

다음과 같이(가 없는 다이아몬드 inheritence):

여기에 내가 존재하는 여러 가지 방법 중 하나를 구현하는 선택적 지연, 고정 지연을 방법은 모두 동일한 독자.각 서브 클래스가 자신의 구현을 지연의 어떤 경우에 당신은 전달을 읽고의 인스턴스 각각의 파생된 지연이다.

class Action // abstract
{
   // Reader and writer would be abstract classes (if not interfaces)
   // from which you would derive to implement the specific
   // read and write protocols.

   class Reader // abstract
   {
      Class Delay {...};
      Delay *optional_delay; // NULL when no delay
      Reader (bool with_delay)
      : optional_delay(with_delay ? new Delay() : NULL)
      {};
      ....
   };

   class Writer {... }; // abstract

   Reader  *reader; // may be NULL if not a reader
   Writer  *writer; // may be NULL if not a writer

   Action (Reader *_reader, Writer *_writer)
   : reader(_reader)
   , writer(_writer)
   {};

   void read()
   { if (reader) reader->read(); }
   void write()
   { if (writer)  writer->write(); }
};


Class Flow : public Action
{
   // Here you would likely have enhanced version
   // of read and write specific that implements Flow behaviour
   // That would be comment to FlowA and FlowB
   class Reader : public Action::Reader {...}
   class Writer : public Action::Writer {...}
   // for Reader and W
   Flow (Reader *_reader, Writer *_writer)
   : Action(_reader,_writer)
   , writer(_writer)
   {};
};

class FlowA :public Flow  // concrete
{
    class Reader : public Flow::Reader {...} // concrete
    // The full implementation for reading A flows
    // Apparently flow A has no write ability
    FlowA(bool with_delay)
    : Flow (new FlowA::Reader(with_delay),NULL) // NULL indicates is not a writer
    {};
};

class FlowB : public Flow // concrete
{
    class Reader : public Flow::Reader {...} // concrete
    // The full implementation for reading B flows
    // Apparently flow B has no write ability
    FlowB(bool with_delay)
    : Flow (new FlowB::Reader(with_delay),NULL) // NULL indicates is not a writer
    {};
};

한 경우 2 지 OneCommand 다만의 특별한 경우 CompositeCommand?을 제거하는 경우 OneCommand 와 허용 CompositeCommands 하는 단 하나의 요소에,나는 당신의 디자인을 가져옵 더 간단하다:

              CommandAbstraction
                 /          \
                /            \
               /              \
        ModernCommand      CompositeCommand
               \               /
                \             /
                 \           /
             ModernCompositeCommand

당신은 여전히 지칠대로 지친 다이아몬드,하지만 나는 생각이 될 수 있습니다 허용되는 경우습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top