Свойства
Свойства - это некоторые значения, хранящиеся в классах/объектах, и описывающие их.
Набор свойств, имеющийся у конкретной сущности, задается в классах, от которых данная сущность наследуется.
Пример использования свойств
class Cat {
//свойство "возраст" целочисленного типа,
// определенное для объектов класса "кот"
obj prop age: int[0, 100] ;
}
obj Basya : Cat {
//Конкретное значение свойства "возраст", присущее объекту "Бася" класса "кот"
age = 2 ;
}
В коде определения свойств представлены классом PropertyDef
Состав базовой хранимой информации:
- Имя свойства (
PropertyDef.name
) - Имя класса, объявившего свойство (
PropertyDef.declaringClassName
) - Тип значения свойства (
PropertyDef.type
) - Вид свойства (
PropertyDef.kind
) - Связанные со свойством метаданные (
PropertyDef.metadata
)
Утверждения о значении свойств представлены классом PropertyValueStatement
Состав базовой хранимой информации:
- Сущность, которой принадлежит значение - класс/объект (
PropertyValueStatement.owner
) - Имя свойства (
PropertyValueStatement.propertyName
) - Задаваемое значение свойства (
PropertyValueStatement.value
)
Объектные и классовые свойства
В системе есть разграничения между объектными и классовыми свойствами. Как следует из названия, это различие определяет, какой сущности могут принадлежать свойства - классам или объектам.
Для аналогии можно опять же вспомнить Java - классовые свойства похожи на static
поля, т.к. принадлежат классам. Объектные же свойства аналогичны обычным полям, т.к. принадлежат отдельным объектам и разнятся от объекта к объекту
Соответственно, значение свойства можно определять только в сущности, соответствующей виду данного свойства
Пример использования различных видов свойств
//класс "Животное"
class Animal {
//свойство "является разумным" является классовым,
// а то есть принадлежит классу и определяется в нем -
// поскольку это свойство не может разниться
// от одного животного к другому внутри одного класса
class prop isSentient : bool = false ;
//свойство "возраст" является объектным,
// а то есть принадлежит объектам класса и определяется в них -
// поскольку это свойство может разниться от одного животного к другому
obj prop age: int[0, 100] ;
}
//класс "Человек", наследуется от "Животного"
class Human : Animal {
//В отличие от static-полей в Java, классовые свойства в нашей системе
// могут наследоваться и переопределяться в классах наследниках.
//Так, "Человек" переопределяет для своих объектов свойство "является разумным"
isSentient = true ;
}
//объект "Петя", инстанс класса "Человек"
obj Petya : Human {
//значение объектного свойства определяется в объекте
age = 20 ;
}
Получение значений свойств
Значения свойств, вне зависимости от их вида и типа, наследуются и могут переопределяться - это можно видеть в примере выше.
На практике это значит, что процесс получения значения свойства для текущей сущности происходит по следующему простому принципу:
- Пока значение не найдено:
- Если текущая сущность определяет значение свойства, вернуть его
- Иначе перейти к родительскому классу текущей сущности
(Именно так реализован код в методе ClassInheritorDef.getPropertyValue()
)
Из этого следует, что с помощью наследования в конкретном объекте можно получить значения свойств, определенных в самом этом объекте или в его родительских классах (т.к. они наследуются)
При этом, конечно, стоит учитывать ограничения, описанные в предыдущем разделе - так, значение объектного свойства можно найти только в самом объекте, а вот значение классового свойства можно быть получено только из его родительских классов.
Типы значений свойств
Любое свойство обязано указывать тип своего значения (поле PropertyDef.type
).
Свойства могут иметь следующие типы:
- Булево значение,
BooleanType
- Целые числа,
IntegerType
- Дробные числа,
DoubleType
- Строки,
StringType
- Перечисления
EnumType
Это обусловлено тем, что только данные типы считаются в системе "примитивными", поскольку они не взаимодействуют с объектной стороной системы (в отличие от типов ClassType
и ObjectType
) - возможность "запихнуть" в значение свойства объект или класс нарушала бы принципы системы. Для подобного связывания между объектами есть отношения.
Параметризация
TODO
Корректность данных (валидация)
Полнота
Класс, объявляющий свойство (PropertyDef.declaringClassName
), должен присутствовать в модели.
В случае, если свойство имеет перечислимый тип (enum), то заданное перечисление должно присутствовать в модели.
Для утверждения о значении свойства, данное свойство должно присутствовать в модели.
Валидность
Свойство, объявленное в конкретном классе, не может иметь имя, повторяющее имя одного из свойств, уже определенных в классе или его классах-родителях.
Значения классовых свойств должны быть определены только в классах, а объектных - в объектах.
Тип значения свойства должен соответствовать объявленному типу свойства.
В случае, если класс является конкретным (в модели существуют объекты, являющиеся прямыми инстансами этого класса), то в нем должны быть определены значения для всех классовых свойств, указанных в нем и его родительских классах (с учетом наследования их значений).
Т.е. не допускается ситуация, когда какой-то объект наследуется от класса, но при этом в цепочке наследования для этого объекта не определено какое-то из свойств класса.