Я знаю, что наличие наследования алмазов считается плохой практикой. Тем не менее, у меня есть два случая, когда я чувствую, что наследование бриллиантов может поместиться очень хорошо. Я хочу спросить, вы бы посоветовали мне использовать наследование алмазов в этих случаях, или есть другой дизайн, который может быть лучше.
Случай 1: Я хочу создавать классы, которые представляют разные виды "действий" в моей системе. Действия классифицируются по нескольким параметрам:
- Действие может быть "Чтение" или "Запись".
- Действие может выполняться с задержкой или без задержки (это не только 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 действия (наследующие от класса Action) не будут реализовывать один и тот же метод.
Случай 2: Я реализую составной шаблон проектирования для "Command" в моей системе. Команда может быть прочитана, записана, удалена и т.д. Я также хочу иметь последовательность команд, которые также могут быть прочитаны, записаны, удалены и т.д. Последовательность команд может содержать другие последовательности команд.
Итак, у меня есть следующий дизайн:
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
};
Кроме того, у меня есть особый вид команд "Modern". Обе команды и составная команда могут быть современными. Будучи "Современным", добавляется определенный список свойств для одной команды и составной команды (в основном одинаковые свойства для них обоих). Я хочу иметь возможность удерживать указатель на 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, будут реализовывать один и тот же метод.
Спасибо.