Автор Тема: Как обозначить атрибут, значение которого вычисляется в момент создания объекта  (Прочитано 2372 раз)

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
Есть класс "Склад" с атрибутом "ФИО Кладовщика", значение атрибута может меняться (не frozen).
Есть класс "Накладная", который связан со "Складом" ассоциацией * к 1 (накладная относится к ровно одному складу, склад связан с любым количеством "Накладных").
Пусть (хоть это и неважно) "Склад" у "Накладной" не может меняться (frozen).
У класса "Накладная" тоже есть атрибут "ФИО Кладовщика", который должен получить значение равное значению атрибута "ФИО Кладовщика" из "Склада" в момент создания "Накладной", и дальше менять значение этого атрибута нельзя.
Как обозначить эту ситуацию на диаграмме классов?
Сделать атрибут "Накладная" "ФИО Кладовщика" frozen мало - надо как-то объяснить как он вычисляется.
Сделать атрибут "Накладная" "ФИО Кладовщика" derived с ограничением "derive: ФИО_Кладовщика = Склад.ФИО_Кладовщика" нельзя - при изменении "Склад" "ФИО Кладовщика" его значение будет изменено.
Сделать атрибут "Накладная" "ФИО Кладовщика" frozen и derived тоже нельзя - это будет означать, что при наличии хотя бы одной "Накладной" у связанного "Склада" не может измениться  значение "ФИО Кладовщика".
Похоже использование derived вообще недопустимо - мы имеем дело не с избыточным элементом, удаление которого не меняет ничего.
Конечно, всегда есть такое средство, как комментарий - пиши, что хочешь! Но ситуация ничего экстраординального из себя не представляет, хотелось обойтись стандартными средствами!
« Последнее редактирование: 16 Мая 2017, 15:48:15 от Vadim »


Galogen

  • Member of CAR
  • Hero Member
  • *****
  • Сообщений: 6093
  • Рейтинг читателей: 194
  • Аксакал
    • Просмотр профиля
    • Профиль в Моем Круге
В момент создание объекта, значение атрибута или задается по умолчанию, или вычисляется задается конструктором.

Атрибуты типа derived вычисляются уже после создания объектов, например появление у родительского объекта новых дочерних объектов: Заказ (число заказанных товаров)- Товар

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
Так как же должно выглядеть описание атрибута по форме видимость ИМЯ кратность : тип = начальное_значение {свойства} (взято из Иванова-Новикова)?
Пока ясно, что среди свойства не должно быть derived и должно быть frozen. Но только frozen мало, надо еще что-то, может быть какие-то constraint?
В момент создание объекта, значение атрибута или задается по умолчанию, или вычисляется задается конструктором.
Как это надо понимать:
  • В момент создание объекта значение атрибута или (a) задается по умолчанию, или (b) вычисляется - задается конструктором.
  • В момент создание объекта значение атрибута или (a) задается по умолчанию, или (b) вычисляется, или (c) задается конструктором.

Galogen

  • Member of CAR
  • Hero Member
  • *****
  • Сообщений: 6093
  • Рейтинг читателей: 194
  • Аксакал
    • Просмотр профиля
    • Профиль в Моем Круге
Так как же должно выглядеть описание атрибута по форме видимость ИМЯ кратность : тип = начальное_значение {свойства} (взято из Иванова-Новикова)?
Пока ясно, что среди свойства не должно быть derived и должно быть frozen. Но только frozen мало, надо еще что-то, может быть какие-то constraint?Как это надо понимать:
  • В момент создание объекта значение атрибута или (a) задается по умолчанию, или (b) вычисляется - задается конструктором.
  • В момент создание объекта значение атрибута или (a) задается по умолчанию, или (b) вычисляется, или (c) задается конструктором.

Вадим.  UML это не язык программирования, а язык проектирования. На этом языке мы предлагаем описание требований или стратегию развития системы.
Сигнатура описания атрибута предполагает некоторый набор свойств. Одно из таких свойств - начальное значение (или значение по умолчанию), которое присваивается атрибуту при создании объекта. Надеюсь это понятно? Создание объекта - это рантайм режим, реализация и выходит за рамки дизайн-тайм, режима проектирования. Какой способ реакции на запись атрибут = начальное значение определяется языком реализации.Типично можно присвоить статическое значение, но в некоторых случаях можно в качестве начального значения использовать какую-то функцию. Возможность этого определяется языком реализации.

Например я создаю таблицу и ставлю на поле Дата создания дефолтное значение  = now(). Что это означает? Только то, что я показал уже реализацию, поскольку не всякая СУБД это воспримет как руководство к действию, а только та, для которой такая функция определена на уровне ядра и имеется внутренняя инструкция как применять.

Т.е. на уровне UML мы используем те средства, что мы имеем, описание через ограничение, заметку или еще как-то.
Итак, если у нас начальное значение = статическое (невычисляемое, а явно задаваемое ) значение - то мы его можем записать явно в сигнатуре определения атрибута
Если начальное значение динамическое, вычисляемое из довольно сложных условий (присвоение даты, присвоение значения в зависимости от значение других объектов и т.п.), то такую задачу можно поручить только конструктору объекта (т.е. вычисляется = задается)

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
UML это не язык программирования, а язык проектирования.
и ещё специфицирования
На этом языке мы предлагаем описание требований или стратегию развития системы.
"ФИО кладовщика в накладной должно совпадать с ФИО кладовщика склада на момент создания накладной" - разве это не требование?
Сигнатура описания атрибута предполагает некоторый набор свойств. Одно из таких свойств - начальное значение (или значение по умолчанию), которое присваивается атрибуту при создании объекта. Надеюсь это понятно?
Присвоение происходит в момент, когда объекта не было и он появляется, или в момент, когда объект был "новый" и стал "не новый"? Может эти моменты совпадают?
Создание объекта - это рантайм режим, реализация и выходит за рамки дизайн-тайм, режима проектирования.
Создание объекта - это рантайм режим, но речь идет не о конкретном объекте, а об общих правилах создания объектов.
Какой способ реакции на запись атрибут = начальное значение определяется языком реализации.Типично можно присвоить статическое значение, но в некоторых случаях можно в качестве начального значения использовать какую-то функцию. Возможность этого определяется языком реализации.

Например я создаю таблицу и ставлю на поле Дата создания дефолтное значение  = now(). Что это означает? Только то, что я показал уже реализацию, поскольку не всякая СУБД это воспримет как руководство к действию, а только та, для которой такая функция определена на уровне ядра и имеется внутренняя инструкция как применять.

Т.е. на уровне UML мы используем те средства, что мы имеем, описание через ограничение, заметку или еще как-то.
Итак, если у нас начальное значение = статическое (невычисляемое, а явно задаваемое ) значение - то мы его можем записать явно в сигнатуре определения атрибута
Если начальное значение динамическое, вычисляемое из довольно сложных условий (присвоение даты, присвоение значения в зависимости от значение других объектов и т.п.), то такую задачу можно поручить только конструктору объекта (т.е. вычисляется = задается)
Конструктор возвращает уже "не новый" объект - все ограничения должны выполняться (у "нового" ограничения могут и не выполняться - некоторые свойства (атрибуты и полюса) имеют "Null" значение)?

Galogen

  • Member of CAR
  • Hero Member
  • *****
  • Сообщений: 6093
  • Рейтинг читателей: 194
  • Аксакал
    • Просмотр профиля
    • Профиль в Моем Круге
и ещё специфицирования
Да, конечно.
Цитировать
"ФИО кладовщика в накладной должно совпадать с ФИО кладовщика склада на момент создания накладной" - разве это не требование?
Требование и что?
Цитировать
Присвоение происходит в момент, когда объекта не было и он появляется, или в момент, когда объект был "новый" и стал "не новый"?

Конструктор создает новый объект - это очевидно, вопрос реанимации объекта в рамках нашей дискуссии? если да, то
1 - возможно создание ранее не существующего объекта. В этом случае его атрибуты принимают значения по умолчанию, если это никак не задано, то Null. Реляционная теория призывает не создавать пустых атрибутов, но типичная ситуация иная, тем более в рамках реализации.
2 - возможна реанимация ранее существующего объекта, т.е. загрузка его в оперативную память, например для отображение данных для формы редактирования. В любом случае объект проходит разные циклы превращения и 2 случай как исходный может включать 1, работа конструктора в таком случае может быт параметризирована (си ++ допускает множество конструкторов)

Цитировать
Может эти моменты совпадают?
Хотелось бы понять что Вы под этим подразумеваете

Цитировать
Создание объекта - это рантайм режим, но речь идет не о конкретном объекте, а об общих правилах создания объектов.Конструктор возвращает уже "не новый" объект - все ограничения должны выполняться (у "нового" ограничения могут и не выполняться - некоторые свойства (атрибуты и полюса) имеют "Null" значение)?
Не понимаю, к чему Вы клоните. Общие правила создания объектов задаются классом, его структурой и методами класса, спецификой его конструктора. Умолчательные значения тоже суть работа конструктора, только в данном случае поднята повыше на абстрактном уровне.

Если провести аналогию с базами данных. Для атрибутов у вас ест правила валидации (default value, validation rules и стандартные процедуры обеспечения целостности, которые определяют значения индексов, первичный и внешних ключей), для любых нестандартных моментов можно использовать триггеры.

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

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
Требование и что?
Любое требование хочется зафиксировать с использованием формальных и, по возможности, визуальных средств (OCL лучше текста, графически лучше OCL).
Если провести аналогию с базами данных.
В БД будет так:
Таблица "Склады" с полями:
  • Ид_Склад, NotNull
  • ФИО_Кладовщика, NotNull
Первичный ключ: Ид_Склад

Таблица "Накладные" с полями:
  • Ид_Склад, NotNull
  • ФИО_Кладовщика, NotNull
Внешний ключ (на таблицу "Склады"): Ид_Склад
 
Новая запись в таблице "Накладные" в качестве значений полей ничего, кроме Null, иметь не может, ведь нет никаких default value. Это первый из моментов, объекта не было и он появился. Дальше кто-то (или что-то) должен позаботиться, чтобы ограничения целостности (оба NotNull, внешний ключ и, конечно, совпадение ФИО Кладовщика) выполнялись - запись может быть сохранена в БД, и сохраняется. Это второй из моментов, объект был "новым" и стал "не новым" - теперь запись ничем не отличается от других.

Galogen

  • Member of CAR
  • Hero Member
  • *****
  • Сообщений: 6093
  • Рейтинг читателей: 194
  • Аксакал
    • Просмотр профиля
    • Профиль в Моем Круге
В БД будет так:
Таблица "Склады" с полями:
  • Ид_Склад, NotNull
  • ФИО_Кладовщика, NotNull
Первичный ключ: Ид_Склад

Таблица "Накладные" с полями:
  • Ид_Склад, NotNull
  • ФИО_Кладовщика, NotNull
Внешний ключ (на таблицу "Склады"): Ид_Склад
 
Новая запись в таблице "Накладные" в качестве значений полей ничего, кроме Null, иметь не может, ведь нет никаких default value. Это первый из моментов, объекта не было и он появился. Дальше кто-то (или что-то) должен позаботиться, чтобы ограничения целостности (оба NotNull, внешний ключ и, конечно, совпадение ФИО Кладовщика) выполнялись - запись может быть сохранена в БД, и сохраняется. Это второй из моментов, объект был "новым" и стал "не новым" - теперь запись ничем не отличается от других.
Если честно не понял, что Вы этим хотели сказать.

[прилетело НЛО и...]

  • Full Member
  • ***
  • Сообщений: 244
  • Рейтинг читателей: 26
    • Просмотр профиля
Попробую, как обычно, внести путаницу.
По стандарту frozen больше нет, есть {readOnly}.
По стандарту объект любого класса создаётся "голеньким", независимо от того, указаны начальные значения атрибутов или нет. Объект создаёт специальная создающая деятельность (её можно рисовать на диаграмме деятельности). Сразу после того как создающая деятельность отработала, запускается инициализирующая деятельность, которая вычисляет начальные значения и присваивает их ({readOnly} и не-{readOnly} атрибутам с начальными значениями). Стандарт пишет, мол, часто инициализирующую деятельность моделируют как конструктор -- операцию с подходящей сигнатурой и стереотипом <<create>>. Конструктору можно указать постусловие. На диаграмме это выглядит как приякоренное к конструктору примечание с пометкой post:. В постусловии можно использовать постфикс @pre, чтобы лишний раз указать, что значение берётся таким, каким оно было до вызова конструктора. Но даже если это не сделать, стандарт определяет момент вычисления выражения, описывающего начальное значение. Т. о. короткое описание того, что в начальном посте:
в Накладной фиоКладовщика:string=Склад.фиоКладовщика {readOnly}
См. 6.3.3 в нижней части стр. 15.
[...и улетело НЛО.]

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
Попробую, как обычно, внести путаницу.
Получилось классное объяснение даже того, что и не было сказано, а нужно было сказать!
По стандарту frozen больше нет, есть {readOnly}.
Лично мне больше нравится frozen из-за того, что я его использую не только в атрибутах и полюсах ассоциаций, но и в обобщениях, когда хочу подчеркнуть тот факт, что если объект начал принадлежать подклассу, то не может его сменить (типа человек: мужчина или женщина).
И еще - сочетание derived и frozen означает, что хотя исходные данные для определения derived могут менять значение, это не должно приводить к изменению значения самого derived. Типа стороны прямоугольника могут и меняться, но так, чтобы его площадь оставалась неизменной.
фиоКладовщика:string=Склад.фиоКладовщика {readOnly}
Мне и хотелось получить нечто подобное по краткости. Но по моим представлением так описывается несколько другая ситуация: да в дальнейшем фиоКладовщика изменяться не сможет, но при заведении накладной в фиоКладовщика можно внести что угодно, просто в качестве начального значения для редактирования будет предложено значение равное Склад.фиоКладовщика, а не пустышка.
« Последнее редактирование: 19 Мая 2017, 16:01:55 от Vadim »

[прилетело НЛО и...]

  • Full Member
  • ***
  • Сообщений: 244
  • Рейтинг читателей: 26
    • Просмотр профиля
Но по моим представлением так описывается несколько другая ситуация: да в дальнейшем фиоКладовщика изменяться не сможет, но при заведении накладной в фиоКладовщика можно внести что угодно, просто в качестве начального значения для редактирования будет предложено значение равное Склад.фиоКладовщика, а не пустышка.
Если просто описать постусловие конструктора и этим ограничиться, то сказанное будет справедливо (у атрибута будет значение по умолчанию, которое после инициализации можно менять). Если к постусловию (или к указанию начального значения) добавляется {readOnly}, это делает значение по умолчанию неизменным в течение всего времени существования объекта (после инициализации).

P. S. Концы ассоциаций могут быть помечены {readOnly}. Но предпочтение тэга/мема дело привычки.
« Последнее редактирование: 19 Мая 2017, 18:34:23 от [прилетело НЛО и...] »
[...и улетело НЛО.]

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
Если просто описать постусловие конструктора и этим ограничиться, то сказанное будет справедливо (у атрибута будет значение по умолчанию, которое после инициализации можно менять). Если к постусловию (или к указанию начального значения) добавляется {readOnly}, это делает значение по умолчанию неизменным в течение всего времени существования объекта (после инициализации).
Я считал, что значение по умолчанию конструктор получает на входе (вместо "пустышки"), а что будет на выходе - определяет сам конструктор. А будет ли в дальнейшем (после конструктора) изменяться значение уже и определяет readonly. В том то и беда: что пойдет на вход конструктору и что можно будет делать после конструктора указать можно, а самое тривиальное поведение конструктора - "ничего не делать, то что получил на вход, то и дай на выход" или "дай на выход вот это" можно указать только в теле конструктора.

Но предпочтение тэга/мема дело привычки.
Я не против readOnly, если читающий знает, что это означает: неизменность значения после инициализации. Но частенько буквальный перевод "только читать" интерпретируют как "нельзя писать", то есть "нельзя редактировать", но другим путем (например вычислять derived атрибут) изменять значение можно!

[прилетело НЛО и...]

  • Full Member
  • ***
  • Сообщений: 244
  • Рейтинг читателей: 26
    • Просмотр профиля
Думаю, тут снова проявляется безалаберность авторов [текста] стандарта.
В книге Dragan Milicev "Model-Driven Development with Executable UML" (pdf-ка есть на bookfi) хорошо разъясняется взгляд на readonly-атрибуты, frozen-атрибуты, выводимые атрибуты. ReadOnly = замороженные сразу после инициализации + без возможности разморозки. NonReadOnly выводимые (по стандарту UML) = обычные атрибуты с единственной особенностью: их значения можно посчитать по другим значениям, но, вообще говоря, неизвестно когда и как посчитать. Отсюда ReadOnly выводимые (по стандарту UML) = замороженные сразу после инициализации + без возможности разморозки атрибуты с единственной особенностью: их значения можно посчитать по другим значениям, но, вообще говоря, неизвестно когда и как посчитать.
Итого: можно ставить слэш перед Накладная::фиоКладовщика {readOnly}, и пытаться отражать "когда" и "где" оно выводится постусловием конструктора. Это не требует делать {readOnly} атрибут Склад::фиоКладовщика.
[...и улетело НЛО.]

Vadim

  • Full Member
  • ***
  • Сообщений: 150
  • Рейтинг читателей: 30
    • Просмотр профиля
В книге Dragan Milicev "Model-Driven Development with Executable UML" (pdf-ка есть на bookfi) хорошо разъясняется взгляд на readonly-атрибуты, frozen-атрибуты, выводимые атрибуты. ReadOnly = замороженные сразу после инициализации + без возможности разморозки. NonReadOnly выводимые (по стандарту UML) = обычные атрибуты с единственной особенностью: их значения можно посчитать по другим значениям, но, вообще говоря, неизвестно когда и как посчитать. Отсюда ReadOnly выводимые (по стандарту UML) = замороженные сразу после инициализации + без возможности разморозки атрибуты с единственной особенностью: их значения можно посчитать по другим значениям, но, вообще говоря, неизвестно когда и как посчитать.
Начал перечитывать Dragan Milicev "Model-Driven Development with Executable UML". Его frozen-атрибуты - это нечто не из UML (хотя явно где-то нужно). А вот про совместное readonly и derived не увидел. Что касается "их значения можно посчитать по другим значениям, но, вообще говоря, неизвестно когда и как посчитать" - он тут говорит скорее о реализации.
Итого: можно ставить слэш перед Накладная::фиоКладовщика {readOnly}, и пытаться отражать "когда" и "где" оно выводится постусловием конструктора.
Если {readOnly} (определяет что будет после инициализации, а точнее, что после инициализации ничего не будет меняться) и есть постусловие конструктора (определяет чем закончится инициализация), то чем отличаются наличие и отсутствие слэша?
Это не требует делать {readOnly} атрибут Склад::фиоКладовщика.
Как правильно это понять:
  • не требует пытаться отражать "когда" и "где" оно выводится постусловием конструктора
  • не требует атрибут Склад::фиоКладовщика делать {readOnly}
?
В исходных данных:
Есть класс "Склад" с атрибутом "ФИО Кладовщика", значение атрибута может меняться (не frozen).

Для меня на данный момент проблема выглядит так:
  • используя readonly и конструктор можно нужную ситуацию описать
  • конструктор использовать не хочется
  • вместо конструктора можно отразить только его постусловие
  • "=defaultValue" не отражает постусловие
  • может "init: Накладная::фиоКладовщика = Склад::фиоКладовщика" отражает постусловие?

[прилетело НЛО и...]

  • Full Member
  • ***
  • Сообщений: 244
  • Рейтинг читателей: 26
    • Просмотр профиля
Его frozen-атрибуты - это нечто не из UML (хотя явно где-то нужно).
Да. Но у него, на мой вкус, внятная позиция по тому, что это такое и как увязываются между собой {readOnly} и {frozen}. Если можно морозить, то можно и разморозить и т. п. Есть другой вариант внятной позиции.

А вот про совместное readonly и derived не увидел.
Совместное получается склеиванием раздельного, т. к. в стандарте оба свойства из метамодели независимы. Мы берём то, что сказано про readonly, и то, что сказано про derived и объединяем. Вот аналогия: теплое и сладкое -- это тёплое + сладкое. По намёкам из текущей версии стандарта выходит, что от соединения теплого и сладкого возникает дополнительный эффект "дрожжей" и градус в модели вдруг повышается.

Что касается "их значения можно посчитать по другим значениям, но, вообще говоря, неизвестно когда и как посчитать" - он тут говорит скорее о реализации.
Тут я тоже вижу удобную предлагаемую трактовку, которая даёт возможность помечать в модели "подозрительный" атрибут, и оставлять реализатору пространство для маневра в поддержке этой "подозрительности".

Если {readOnly} (определяет что будет после инициализации, а точнее, что после инициализации ничего не будет меняться) и есть постусловие конструктора (определяет чем закончится инициализация), то чем отличаются наличие и отсутствие слэша?
Если слэша нет, то о привязке к другому значению мы узнаём только из постусловия. Если слэш есть, то наше внимание дважды акцентируется на непростом атрибуте.

Как правильно это понять ... не требует атрибут Склад::фиоКладовщика делать {readOnly}?
Второе. Извините за невнятность.

В исходных данных:
Для меня на данный момент проблема выглядит так:
  • используя readonly и конструктор можно нужную ситуацию описать
  • конструктор использовать не хочется
  • вместо конструктора можно отразить только его постусловие
  • "=defaultValue" не отражает постусловие
  • может "init: Накладная::фиоКладовщика = Склад::фиоКладовщика" отражает постусловие?
"=defaultValue" отражает постусловие конструктора в той части, в которой важно. И "init: Накладная::фиоКладовщика = Склад::фиоКладовщика" тоже. Просто в этих двух выражениях нет явной привязке ко времени, когда берётся присваиваемое значение. Эта привязка неявная, данная стандартом в пояснении к defaultValue. Постусловие, как мне кажется, нагляднее говорит о временнОй привязке. Выше писало про @pre, его можно [с некоторой тонкостью] использовать, что явно скажет о том, когда используется значение.
[...и улетело НЛО.]