Я хочу создать диаграмму классов 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)"
}
Все атрибуты класса являются закрытыми, а общедоступные получают общедоступные геттеры/сеттеры:
Я использовал эти два ответа на Stackoverflow для аннотаций <<get/set>> (см. здесь ) и атрибута {readOnly} ( см. здесь).
@qwerty_so Я действительно запутался, пожалуйста, объясните подробнее.
@AliDehkhodaei Спасибо за этот интересный вопрос, для которого вы провели небольшое исследование! Я сделал некоторые правки, чтобы облегчить чтение. Пожалуйста, не стесняйтесь редактировать, если я что-то исказил.
@qwerty_so Я полностью согласен. Но, видимо, OP не пытается кодировать в UML, а просто документирует существующий код. И, честно говоря, UML также не зависит от его использования ;-) Кстати, OP ссылается на один из ваших интересных ответов, который я обнаружил благодаря его ссылке ;-)
Я также нашел это для С# github.com/pierre3/PlantUmlClassDiagramGenerator. Он предоставляет некоторые подробности для uml, такие как readOnly и <<get>><<set>>.
@Christophe Намерение показать геттер/сеттер связано с желанием показать детали кодирования. Я бы предпочел закрыть этот вопрос как дубликат ответа Герта. (кстати, вы затерли ссылку (и)) своим редактированием.
@qwerty_so Я скорее думаю, что ответ Герта здесь не актуален, и он больше касается отображения в UML некоторых особенностей, связанных с языком, которые находятся в серой зоне (например, здесь для свойств C#).
@AliDehkhodaei Интересная ссылка на GitHub. Как видите, генератор добавляет стереотип get/set только для тех свойств, которые его определяют. Нет необходимости определять их для общедоступного атрибута.
Но в моем примере имя и адрес имеют неявный геттер и сеттер. Разве я не должен определять этот get/set?





Как написано в вашей первой ссылке , нет такого стандарта, как <<get/set>> или {readOnly}, но ничто не мешает вам использовать его (также показано здесь), если это нормально в вашей команде.
Ваш первый вариант - ванильный (я позвоню) UML, за исключением того, что name и address должны быть общедоступными.
Почему вы добавили следующие методы, когда у меня их нет? | - getNumCourses(): Int | | - setNumCourses(): Unit | | - getCourses(): Array<String> | | - getGrades(): IntArray |
@AliDehkhodaei, вы правы, я принял частные поля за вспомогательное поле (геттер / сеттер)
Могу я предложить прочитать ссылку, связанную с {readOnly}, до конца? Вы обнаружите, что это 100% стандартный UML. Затем стоит упомянуть, что добавление стереотипов (например, «my new stereotype») — это стандартный способ улучшить UML. Любой приличный инструмент моделирования позволяет вам определить свои собственные - вопрос только в том, чтобы увидеть, есть ли уже какие-то общеупотребительные стереотипы для этой конкретной проблемы (и «получить» «установить», кажется, выиграть битву с менее точным «свойством», также для других языков: stackoverflow.com/q/470097/3723423 )
Давайте не будем усложнять. Я читал, что свойства Kotlin изменяются при определении с помощью var и читаются только при определении с помощью val. Я вижу в вашем коде два общедоступных и три частных свойства.
Глядя на определение свойства UML и правила доступности UML, это очень просто переводится как:
+ name: String {readOnly}
+ address: String
- numCourses: Int=0
- courses: String[MAX_COURSES]
- grades: Int[MAX_COURSES]
Еще несколько пояснений:
{readOnly}, это было бы применимо ко всем элементам MAX_COURSES, а это означает, что вы могли бы определить их значения только один раз и не изменять их впоследствии (т.е. оставаться навсегда ""): это не то, что вы хотите выразить.Дополнительные замечания:
Для свойства Kotlin xyz с геттерами и сеттерами, использующими резервное свойство, вам не нужно ничего, кроме стандартной нотации UML производного свойства: /xyz. Спецификации UML объясняют, что:
Но там, где производное свойство является изменяемым, ожидается, что реализация внесет соответствующие изменения в модель, чтобы удовлетворить все ограничения, в частности, ограничение производного свойства для производного свойства. Вывод для производного свойства может быть указан ограничением.
Если бы вы определили в своем классе явные геттеры и сеттеры и резервное поле, вы могли бы использовать стереотипы «get», «set», чтобы сообщить, что за сценой могут быть некоторые операции. Для свойств в интерфейсах я бы сделал это систематически, чтобы уточнить, что должны предоставлять реализующие классы.
Спасибо большое, Только за интерфейсы? If you would use Kotlin properties in an interface
@AliDehkhodaei "или если бы вы определили ..." - я хотел сказать, что в интерфейсе я бы делал это систематически (потому что классы, реализующие интерфейс, должны знать, что предоставлять) - но в других случаях я использовал бы его, когда геттеры и сеттеры указаны явно.
Проблема в вашем вопросе заключается в том, что вы начинаете с кода и хотите его документировать. Так что вам понадобятся простые правила транскрипции. Однако во многих случаях с точки зрения дизайна вы должны документировать в UML некоторые ограничения (например, {hour>=0 and hour<=24}), а установщики — это только детали реализации (т. е. то, как ограничение применяется в коде).
Спасибо. 1. Измените - Оценки: String[MAX_COURSES] на - Оценки: Int[MAX_COURSES]. 2. Можете показать backing property в uml на примере?
@AliDehkhodaei Нет причин задавать дополнительные вопросы в комментарии. Если у вас есть такие: откройте новый вопрос.
UML как таковой не зависит от языка. Он предназначен для моделирования идей на относительно абстрактном уровне - без необходимости думать о конкретных деталях языка программирования (PL). Модель UML можно дополнить, чтобы она ориентировалась на определенный ЯП. Однако это редко бывает хорошей идеей. Когда вы делаете модель, вы абстрагируетесь от конкретной вещи, облегчая обращение с ней.
У кого-то может возникнуть соблазн «перекодировать» в UML при документировании существующего кода. Плохая идея, так как вы упускаете суть.
Сказав это, я могу только присоединиться к тому, что сказал Кристоф в своем ответе, и его UML, вероятно, является самым простым для выражения сути.
tl;dr Как сказал Эйнштейн: делайте вещи максимально простыми, но не проще. Иногда это сложно...
Кажется, вы не понимаете смысла UML: он не зависит от языка. Если вы хотите кодировать, тогда кодируйте. Если вы хотите моделировать, используйте UML. Но не кодируйте в UML.