Редактирование данных
#
Васильев Андрей Михайлович, 2024
Версии презентации
Работа со сложными структурами данных
#
При работе со сложными вложенными структурами приходится решать вопрос по
получению и изменению свойств вложенных элементов
Рассмотрим следующие структуры данных
data class AcademicClass(val id: Int, val name: String,
val teacher: String)
data class Course(val id: Int, val name: String,
val clasess: List<AcademicClass>)
data class Speciality(val id: Int, val name: String,
val courses: List<Course>)
val speciality: Speciality = ...
Используем неизменяемые структуры данных, чтобы предотвратить проблемы
конкурентного доступа и модификации
Модификация структур данных
#
Для получения информации по предмету необходимо найти курс в списке, найти
предмет, обратиться к полям класса для получения:
val class = speciality.courses[1].classes[5]
Для редактирования потребуется выполнить несколько копирований:
val newAcademicClass = speciality.courses[1].classes[5]
.copy(name = "Безопасность жизнедеятельности")
val newAcademicClasses = speciality.courses[1].classes.toMutableList()
.apply { set(5, newAcademicClass) }
val newCourse = speciality.courses[1].copy(classes = newAcademicClasses)
val newCourses = speciality.courses.toMutableList()
.apply { set(1, newCourse) }
val newSpeciality = speciality.copy(courses = newCourses)
Можно создать новую версию неизменяемых данных с нужным состоянием, остаётся
только сохранить новую копию в общем хранилище приложения
Сложные структуры сложны
#
Сильная вложенность структур данных несёт следующие проблемы:
- Надо корректно указать путь к данным несколько раз
- Необходимо написать много кода
- Возможны технические ошибки
- Код, которому нужен доступ только к конечным данным, начинает зависеть от всех
промежуточных объектов, что усложняет изменение структур данных в приложении
Решение с помощью функций (операций)
#
Мы можем ввести функции (или операции), позволяющие решить данные задачи:
fun getName(speciality: Speciality, courseId: Int, classId: Int): String
fun setName(name: String, speciality: Speciality,
courseId: Int, classId: Int): Speciality
Код будет зависеть только от класса Speciality и одной из указанных функций
Моделирование связных списков
#
В рамках приложения данные зачастую представлены в виде списков данных:
список групп, список студентов, список предметов
Элементы списков зачастую связаны с объектами из других списков
При моделировании связей между объектами в приложении кажется удобным подход с
хранением ссылок на связные объекты:
data class Course(
val id: Int,
val name: String,
val clasess: List<AcademicClass>,
)
- Эта структура оптимизирована под задачу получения всех предметов курса
- Структура не оптимизирована для других задач, например на поиск списка
предметов, которые ведёт один преподаватель
Подход к моделированию списков данных
#
- Каждый элемент хранится только в своём хранилище
- Для связи элемента из одного списка с элементом из другого списка используется
не ссылка на объект, а уникальный идентификатор элемента
- Хранилище оптимизируется для получения элемента по идентификатору
В примере выше:
- У сущности предмет добавляется идентификатор курса, в которой он преподаётся
- У курса добавляется идентификатор специальности
Подход применим не только для списков данных, но и для связи один-к-одному
Модели классов и курсов
#
Оригинальные структуры данных
data class AcademicClass(val id: Int, val name: String,
val teacher: String)
data class Course(val id: Int, val name: String,
val clasess: List<AcademicClass>)
data class Speciality(val id: Int, val name: String,
val courses: List<Course>)
Модифицированные структуры данных
data class AcademicClass(val id: Int, val name: String,
val teacher: String, val courseId: Int)
data class Course(val id: Int, val name: String, val specialityId: Int)
data class Speciality(val id: Int, val name: String)
Хранилище для предметов:
class AcademicClassStorage() {
fun fetch(classId: Int): AcademicClass? { ... }
fun list(): List<AcademicClass> { ... }
fun add(academicClass: Class): Int { ... }
fun update(academicClass: Class) { ... }
fun remove(classId: Int) { ... }
}
Изменение данных хранилищ
#
Для выполнения операций над несколькими списками вводите операции, которые
обращаются с несколькими хранилищами
Операция над данными
#
Операции редактирования
#
- Операции редактирования реализуются очень просто, т.к. достаточно иметь только
ссылку на соответствующее хранилище
- Для обеспечения корректности ссылок можно передать ссылки на соответствующие
хранилища, с помощью которых проверять наличие данных по указанным ссылкам
Операции извлечения данных
#
- Хранятся ссылки на хранилища, из которых необходимо извлечь данные
- Результат работы — наборы данных, в структурах данных, наиболее удобных для их
обработки на стороне получателя
Например для задачи поиска предметов, преподаваемых конкретным преподавателем
data class TeacherClasess(val teacher: String,
val classes: List<AcademicClass>)
class FindTeacherClasses(private val academicClassStorage) {
fun findByTeacher(teacher: String): TeacherClasses
}