Какая диаграмма классов UML более точна для атрибутов класса Kotlin?

Я хочу создать диаграмму классов UML для представления класса Kotlin. Я наткнулся на несколько вариантов и придумал два варианта. Однако я не уверен, какой из двух является наиболее подходящим и точным. Может ли кто-нибудь помочь мне определить, какая диаграмма UML правильна или лучше для этого класса Kotlin?

Вот класс Kotlin, который я хочу представить:

class Student(val name: String, var address: String) {

    private var numCourses: Int = 0

    private val courses: Array<String> = Array(MAX_COURSES) { "" }

    private val grades: IntArray = IntArray(MAX_COURSES)
    companion object {
        const val MAX_COURSES = 30
    }

    fun printGrades() {
        print(name)
        for (i in 0 until numCourses) {
            print(" ${courses[i]}:${grades[i]}, ")
        }
        println()
    }

    fun calculateAverageGrade() = grades.sum().toDouble() / grades.size

    fun addCourseGrade(course: String, grade: Int) {

        require(numCourses < MAX_COURSES) {
            "A student cannot take more than $MAX_COURSES courses"
        }

        require(grade in 0..100) {
            "Grade must be between 0 and 100"
        }

        courses[numCourses] = course
        grades[numCourses] = grade
        numCourses++
    }

    override fun toString() = "name($address)"

}

Вариант 1: с геттерами и сеттерами

Все атрибуты класса являются закрытыми, а общедоступные получают общедоступные геттеры/сеттеры:

Вариант 2: использование некоторых дополнительных нотаций UML

Я использовал эти два ответа на Stackoverflow для аннотаций <<get/set>> (см. здесь ) и атрибута {readOnly} ( см. здесь).

Кажется, вы не понимаете смысла UML: он не зависит от языка. Если вы хотите кодировать, тогда кодируйте. Если вы хотите моделировать, используйте UML. Но не кодируйте в UML.

qwerty_so 16.07.2023 11:17

@qwerty_so Я действительно запутался, пожалуйста, объясните подробнее.

Ali Dehkhodaei 16.07.2023 11:40

@AliDehkhodaei Спасибо за этот интересный вопрос, для которого вы провели небольшое исследование! Я сделал некоторые правки, чтобы облегчить чтение. Пожалуйста, не стесняйтесь редактировать, если я что-то исказил.

Christophe 16.07.2023 12:25

@qwerty_so Я полностью согласен. Но, видимо, OP не пытается кодировать в UML, а просто документирует существующий код. И, честно говоря, UML также не зависит от его использования ;-) Кстати, OP ссылается на один из ваших интересных ответов, который я обнаружил благодаря его ссылке ;-)

Christophe 16.07.2023 12:29

Я также нашел это для С# github.com/pierre3/PlantUmlClassDiagramGenerator. Он предоставляет некоторые подробности для uml, такие как readOnly и <<get>><<set>>.

Ali Dehkhodaei 16.07.2023 12:40

@Christophe Намерение показать геттер/сеттер связано с желанием показать детали кодирования. Я бы предпочел закрыть этот вопрос как дубликат ответа Герта. (кстати, вы затерли ссылку (и)) своим редактированием.

qwerty_so 16.07.2023 13:19

@qwerty_so Я скорее думаю, что ответ Герта здесь не актуален, и он больше касается отображения в UML некоторых особенностей, связанных с языком, которые находятся в серой зоне (например, здесь для свойств C#).

Christophe 16.07.2023 14:25

@AliDehkhodaei Интересная ссылка на GitHub. Как видите, генератор добавляет стереотип get/set только для тех свойств, которые его определяют. Нет необходимости определять их для общедоступного атрибута.

Christophe 16.07.2023 14:38

Но в моем примере имя и адрес имеют неявный геттер и сеттер. Разве я не должен определять этот get/set?

Ali Dehkhodaei 16.07.2023 14:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Как написано в вашей первой ссылке , нет такого стандарта, как <<get/set>> или {readOnly}, но ничто не мешает вам использовать его (также показано здесь), если это нормально в вашей команде.

Ваш первый вариант - ванильный (я позвоню) UML, за исключением того, что name и address должны быть общедоступными.

Почему вы добавили следующие методы, когда у меня их нет? | - getNumCourses(): Int | | - setNumCourses(): Unit | | - getCourses(): Array<String> | | - getGrades(): IntArray |

Ali Dehkhodaei 16.07.2023 11:07

@AliDehkhodaei, вы правы, я принял частные поля за вспомогательное поле (геттер / сеттер)

Jemshit 16.07.2023 11:19

Могу я предложить прочитать ссылку, связанную с {readOnly}, до конца? Вы обнаружите, что это 100% стандартный UML. Затем стоит упомянуть, что добавление стереотипов (например, «my new stereotype») — это стандартный способ улучшить UML. Любой приличный инструмент моделирования позволяет вам определить свои собственные - вопрос только в том, чтобы увидеть, есть ли уже какие-то общеупотребительные стереотипы для этой конкретной проблемы (и «получить» «установить», кажется, выиграть битву с менее точным «свойством», также для других языков: stackoverflow.com/q/470097/3723423 )

Christophe 16.07.2023 12:41
Ответ принят как подходящий

Давайте не будем усложнять. Я читал, что свойства Kotlin изменяются при определении с помощью var и читаются только при определении с помощью val. Я вижу в вашем коде два общедоступных и три частных свойства. Глядя на определение свойства UML и правила доступности UML, это очень просто переводится как:

+ name: String {readOnly}
+ address: String 
- numCourses: Int=0
- courses: String[MAX_COURSES] 
- grades: Int[MAX_COURSES] 

Еще несколько пояснений:

  • Здесь не нужно ничего добавлять о геттерах и сеттерах, если вы не реализуете геттеры и сеттеры явно. Вопрос, на который вы ссылались, касался дизайна, в котором все свойства хранятся в частном порядке и доступны через явные геттеры и сеттеры. Вы этого не делаете, значит, вам это не нужно.
  • В вашем коде вы не определяете размер массива как магическое число 30. Так что придерживайтесь этой хорошей практики и в UML и используйте кратность MAX_COURSES, которая является постоянным значением.
  • существует важное семантическое различие между массивами Kotlin и множествами UML. В Kotlin массив доступен только для чтения, потому что создается один массив, и этот объект массива фиксированного размера не модифицируется. Однако вы по-прежнему можете изменять содержащиеся в нем объекты. В UML нет массива; кратность говорит о том, что есть свойства MAX_COURSES (без подробностей о том, как это реализовано). Если бы вы использовали {readOnly}, это было бы применимо ко всем элементам MAX_COURSES, а это означает, что вы могли бы определить их значения только один раз и не изменять их впоследствии (т.е. оставаться навсегда ""): это не то, что вы хотите выразить.

Дополнительные замечания:

  • Для свойства Kotlin xyz с геттерами и сеттерами, использующими резервное свойство, вам не нужно ничего, кроме стандартной нотации UML производного свойства: /xyz. Спецификации UML объясняют, что:

    Но там, где производное свойство является изменяемым, ожидается, что реализация внесет соответствующие изменения в модель, чтобы удовлетворить все ограничения, в частности, ограничение производного свойства для производного свойства. Вывод для производного свойства может быть указан ограничением.

  • Если бы вы определили в своем классе явные геттеры и сеттеры и резервное поле, вы могли бы использовать стереотипы «get», «set», чтобы сообщить, что за сценой могут быть некоторые операции. Для свойств в интерфейсах я бы сделал это систематически, чтобы уточнить, что должны предоставлять реализующие классы.

Спасибо большое, Только за интерфейсы? If you would use Kotlin properties in an interface

Ali Dehkhodaei 16.07.2023 14:37

@AliDehkhodaei "или если бы вы определили ..." - я хотел сказать, что в интерфейсе я бы делал это систематически (потому что классы, реализующие интерфейс, должны знать, что предоставлять) - но в других случаях я использовал бы его, когда геттеры и сеттеры указаны явно.

Christophe 16.07.2023 14:41

Проблема в вашем вопросе заключается в том, что вы начинаете с кода и хотите его документировать. Так что вам понадобятся простые правила транскрипции. Однако во многих случаях с точки зрения дизайна вы должны документировать в UML некоторые ограничения (например, {hour>=0 and hour<=24}), а установщики — это только детали реализации (т. е. то, как ограничение применяется в коде).

Christophe 16.07.2023 14:52

Спасибо. 1. Измените - Оценки: String[MAX_COURSES] на - Оценки: Int[MAX_COURSES]. 2. Можете показать backing property в uml на примере?

Ali Dehkhodaei 17.07.2023 11:12

@AliDehkhodaei Нет причин задавать дополнительные вопросы в комментарии. Если у вас есть такие: откройте новый вопрос.

qwerty_so 17.07.2023 11:23

UML как таковой не зависит от языка. Он предназначен для моделирования идей на относительно абстрактном уровне - без необходимости думать о конкретных деталях языка программирования (PL). Модель UML можно дополнить, чтобы она ориентировалась на определенный ЯП. Однако это редко бывает хорошей идеей. Когда вы делаете модель, вы абстрагируетесь от конкретной вещи, облегчая обращение с ней.

У кого-то может возникнуть соблазн «перекодировать» в UML при документировании существующего кода. Плохая идея, так как вы упускаете суть.

Сказав это, я могу только присоединиться к тому, что сказал Кристоф в своем ответе, и его UML, вероятно, является самым простым для выражения сути.

tl;dr Как сказал Эйнштейн: делайте вещи максимально простыми, но не проще. Иногда это сложно...

Другие вопросы по теме