Я новичок в UML, поэтому у меня есть несколько вопросов об обобщении и реализации. Я моделирую поведение электронного микроконтроллера, и мне нужно сгенерировать код C++ из описания UML.
Насколько мне известно, класс реализует интерфейс, то есть он может обеспечивать реализацию интерфейса. Между двумя классами может существовать отношение обобщения. В этом случае производный класс наследует все члены базового класса и получает доступ к общедоступным и защищенным членам.
Вот мой вопрос (я использую Visual Paradigm в качестве инструмента моделирования). Предположим, у нас есть модуль микроконтроллера, а именно Timer
. У нас есть набор операций, которые мы можем выполнять, скажем, initTimer()
, startTimer()
, stopTimer()
и так далее. На самом деле эти функции определяют своего рода API. У нас могут быть разные классы Timer
, скажем, TimerA
, TimerB
, TimerC
, которые наследуют (или реализуют?) все указанные операции. Картинка, наверное, сделает сценарий более понятным. [C] означает классификатор.
+----------------------------------+
| <<SW>> |
| <<Singleton>> |
+--------------| TimerA |
| +----------------------------------+
| | -instance : TimerA* = null [C] |
| | -instanceFlag : bool = false [C] |
| | -moduleAddress const = 0x0010 |
| +----------------------------------+
| | -TimerA() |
V | +getInstance() : TimerA* [C] |
+---------------+ +----------------------------------+
| <<SW>> |
| Timer |
+---------------+
| +initTimer() |
| +startTimer() |<-----------------------+
| +stopTimer() | |
+---------------+ +----------------------------------+
| <<SW>> |
| <<Singleton>> |
| TimerB |
+----------------------------------+
| -instance : TimerB* = null [C] |
| -instanceFlag : bool = false [C] |
| -moduleAddress const = 0x0020 |
+----------------------------------+
| -TimerB() |
| +getInstance() : TimerB* [C] |
+----------------------------------+
Visual Paradigm позволяет пользователю размещать код внутри каждой функции. Я спрашиваю вас, какие отношения должны быть у стрелок.
1) Обобщение: Timer
класс с набором операций. Каждая операция имеет свою кодовую реализацию. Два производных класса TimerA
и TimerB
со ссылкой на обобщение, наследующие операции класса Timer
.
2) Реализация: Timer
— это интерфейс (а не класс, как показано) и два класса реализации TimerA
и TimerB
. Критический момент заключается в следующем. Хотя Timer — это интерфейс, и его операции не должны содержать деталей реализации, VP позволяет писать код реализации для трех операций. Во время генерации кода создается интерфейс C++ класса Timer
: initTimer()
, startTimer()
и stopTimer()
являются виртуальными членами класса Timer
без кода (как и должно быть). Создается класс C++ TimerA
, который наследует члены класса Timer
; кроме того, три операции Timer
копируются среди членов TimerA
с реализацией кода, который я написал для операций класса интерфейса. Это происходит и для TimerB
.
На ваш взгляд, какое из двух описаний лучше? Правильно ли писать реализацию кода для операций интерфейса, даже если я знаю, что после генерации кода они будут переданы реализующим классам?