2010-06-01 2 views
1

Это мое приложение для моделирования полета снова. Сейчас я покидаю простой этап прототипирования и начинаю разрабатывать дизайн программного обеспечения. По крайней мере, я стараюсь.Использовать множественное наследование для различения ролей использования?

У каждого из самолетов в симуляции есть связанный с ними план полета, точный характер которого не представляет интереса для этого вопроса. Достаточно сказать, что операторский способ редактировать план полета во время симуляции. Самолетная модель большую часть времени должна только считывать объект плана полета, который сначала считал необходимым просто передать ссылку на константу. Но, предположительно, самолет должен будет позвонить AdvanceActiveWayPoint(), чтобы указать, что точка пути достигнута. Это повлияет на Iterator, возвращаемый функцией ActiveWayPoint(). Это означает, что модель самолета действительно нуждается в неконстантной ссылке, которая, в свою очередь, также предоставит модели самолета модели AppendWayPoint(). Я хотел бы избежать этого, потому что я хотел бы обеспечить соблюдение правила использования, описанного выше во время компиляции.

Обратите внимание, что class WayPointIter эквивалентен итератору STL const, то есть точка не может быть мутирована итератором.

class FlightPlan 
{ 
public: 
    void AppendWayPoint(const WayPointIter& at, WayPoint new_wp); 
    void ReplaceWayPoint(const WayPointIter& ar, WayPoint new_wp); 
    void RemoveWayPoint(WayPointIter at); 

    (...) 

    WayPointIter First() const; 
    WayPointIter Last() const; 
    WayPointIter Active() const; 

    void AdvanceActiveWayPoint() const; 

    (...) 
}; 

Моей идеей преодолеть проблему является следующее: определить абстрактный класс интерфейса для каждой роли использования и наследовать FlightPlan от обоих. Затем каждый пользователь получает только ссылку на соответствующую роль использования.

class IFlightPlanActiveWayPoint 
{ 
public: 
    WayPointIter Active() const =0; 
    void AdvanceActiveWayPoint() const =0; 
}; 

class IFlightPlanEditable 
{ 
public: 
    void AppendWayPoint(const WayPointIter& at, WayPoint new_wp); 
    void ReplaceWayPoint(const WayPointIter& ar, WayPoint new_wp); 
    void RemoveWayPoint(WayPointIter at); 

    (...) 

}; 

Таким образом, декларация FlightPlan нужно только быть изменен на:

class FlightPlan : public IFlightPlanActiveWayPoint, IFlightPlanEditable 
{ 
    (...) 
}; 

Что вы думаете? Есть ли какие-нибудь пропахи, которых я могу пропустить? Является ли эта конструкция ясной или мне придумать что-то другое для ясности?

В качестве альтернативы я мог бы также определить специальный класс ActiveWayPoint, который будет содержать функцию AdvanceActiveWayPoint(), но считайте, что это может быть ненужным.

Заранее благодарен!

ответ

1

С точки зрения строгого дизайна, ваша идея действительно хороша. Это эквивалентно наличию одного объекта и нескольких разных «представлений» над этим объектом.

Однако здесь существует проблема масштабирования (относящаяся к реализации). Что делать, если у вас есть другой объект Foo, которому нужен доступ к расписанию, вы бы добавили интерфейс IFlightPlanFoo?

Существует риск, что вы скоро столкнетесь с imbroglio в наследстве.

Традиционный подход заключается в создании другого объекта, Proxy, и использовать этот объект для адаптации/ограничения/управления использованием. Это шаблон дизайна: Proxy

Здесь вы можете создать:

class FlightPlanActiveWayPoint 
{ 
public: 
    FlightPlanActiveWayPoint(FlightPlan& fp); 

    // forwarding 
    void foo() { fp.foo(); } 

private: 
    FlightPlan& mFp; 
}; 

Дайте ему интерфейс, который запланирован на IFlightPlanActiveWayPoint, строить со ссылкой на фактический FlightPlan объекта, и переадресовать вызовы.

Есть несколько преимуществ такого подхода:

  • Зависимость: это ненужным редактирование flightPlan.h каждый раз, когда у вас есть новое требование, таким образом, нет необходимости в восстановлении всего приложения
  • Это быстрее, потому что нет никакого виртуального звоните дольше, и функции могут быть встроены (таким образом, почти ничего). Хотя я бы рекомендовал не включать их для начала (так что вы можете их модифицировать, не перекомпилируя все).
  • Это легко добавлять проверки/регистрации и т.д. без изменения базового класса (в случае, если у вас есть проблемы в конкретном сценарии)

Мои 2 цента.

+0

Спасибо! Возможность включения протоколирования и дополнительных проверок является точкой, которую я считаю очень ценным дополнением. – Arne

0

Не уверен насчет «cavecats» ;-), но разве экипаж самолета иногда не модифицировал сам план полета в реальной жизни? Например. если впереди плохая буря, или аэропорт назначения недоступен из-за густого тумана. В кризисных ситуациях право капитана самолета принимать окончательное решение. Конечно, вы можете не включать это в свою модель, но я подумал, что это стоит упомянуть.

Альтернативой множественному наследованию может быть композиция с использованием изменения Pimpl idiom, в котором класс-оболочка не будет раскрывать полный интерфейс внутреннего класса. Как отмечает @Matthieu, это также известно как вариация шаблона проектирования прокси.

+0

хорошо, вы правы. В этом случае ситуация несколько отличается. Моделирование предназначено для воздушного движения в терминальной зоне аэропорта. Предполагается, что любое отклонение от заранее запланированного плана полета является результатом команды, выданной диспетчером воздушного движения на земле. – Arne

+0

@ Арне, я вижу, спасибо за разъяснение. –

Смежные вопросы