Дочерняя структура зависит от родительского свойства

У меня есть несколько взаимосвязанных объектов:

Упражнения

Например, отжимания, подтягивания, приседания. Каждое упражнение имеет название, задействованные мышцы (грудь, ноги...), шаги выполнения и тип категории.

Категория упражнений

Это перечисление, которое показывает, как измеряется это упражнение.

  • Например, «отжимание» — это тип bodyweightReps, как вы необходимо измерять только выполненные повторения.
  • «Приседания со штангой» — это тип weightReps, при котором вы фиксируете как вес на штанге, так и количество выполненных повторений.
  • Таким образом, каждое упражнение можно измерить с разными параметрами и с разным количеством параметров:
    • bodyweightReps нужно записать только 1 параметр repetition,
    • а weightReps нужно 2, 1 для weight и 1 для repetition).
  • На данный момент все упражнения можно измерить максимум по двум параметрам, но в будущем это может измениться.

Тренировка

Это действие, выполняемое во время тренировки. В нем есть упражнение, некоторые примечания и список выполненных комплексов тренировок.

Тренировочный комплекс

Это комплекс тренировок. Он имеет время отдыха и список показателей для сохраненных значений (например, количество выполненных повторений, использованный вес...).
measures набора тренировок зависит от родительской категории упражнений «Тренировка», так как набор тренировок со штангой «Приседания со штангой» требует измерения веса и количества выполненных повторений, так как категория упражнений — weightReps.

Как видите, WorkoutActivity имеет упражнение, а структура дочернего свойства WorkoutSet Measures зависит от родительского свойства категории упражнений WorkoutActivity.

enum ExerciseType {
 weightReps,
 bodyWeightReps,
 distance,
 time
}

class Exercise {
 String name;
 List<String> executionSteps;
 ExerciseType category;
}

class Workout {
 String name
 List<WorkoutActivity> activities;
}

class WorkoutActivity {
 String note;
 Exercise exercise;
 List<WorkoutSet> sets;
}

class WorkoutSet {
 int restTime;
 List<double> measures;
}

Проблема

Приведенная выше структура не гарантирует, что наборы тренировок тренировки, тип категории упражнений которых bodyweightReps, имеют только одну меру, а также то, что если тип категории weightReps имеет 2 меры.

Эта проблема поднимает некоторые связанные проблемы, которые нельзя игнорировать.

Есть ли лучший способ структурировать сущности, чтобы показатели дочернего WorkoutSet можно было заставить следовать структуре типа родительской категории упражнений Workout Activity?

Хотите ли вы иметь гарантии времени выполнения или компиляции?

Peter Csala 02.06.2024 07:55

Предпочтительно время компиляции, но допускается и время выполнения :)

salim.elkh 02.06.2024 08:37

О каком языке мы говорим? Моё обоснованное предположение - C#...

Peter Csala 02.06.2024 09:10

Я использую dart для Flutter, но более или менее могу расшифровать другие языки, большое спасибо!

salim.elkh 02.06.2024 09:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В .NET 5 было введено несколько новых атрибутов анализа кода, например MemberNotNullWhen. Было бы полезно, если бы внутри WorkoutSet были выделены поля для показателей weight и repetition.

Поскольку у нас есть набор мер и мы говорим о разных языках программирования, позвольте мне начать с простого примера.

Для простоты я переместил ExerciseType на WorkoutSet.

abstract class WorkoutSet 
{
    ExerciseType category;
    int restTime;
    List<double> measures;
    
    public sealed class WeightReps : WorkoutSet
    {
        public WeightReps (int restSeconds, double repetition, double weight )
        {
            this.category = ExerciseType.weightReps;
            this.restTime = restSeconds;
            this.measures = new() { repetition, weight };
        }
    }

    public sealed class BodyWeightReps : WorkoutSet
    {
        public BodyWeightReps (int restSeconds, double repetition )
        {
            this.category = ExerciseType.bodyWeightReps;
            this.restTime = restSeconds;
            this.measures = new() { repetition };
        }
    }
}

Это позволит вам создать класс WeightReps или BodyWeightReps. Их конструкторы получают необходимое количество параметров и знают, как инициализировать данный экземпляр. Вы не можете напрямую создать WorkoutSet.

new WorkoutSet.BodyWeightReps((int)data.rest.TotalSeconds, data.repetition)

new WorkoutSet.WeightReps((int)data.rest.TotalSeconds, data.repetition, data.weight);

В случае C# вы можете продвинуть эту идею немного дальше с помощью неявных операторов для автоматического преобразования ValueTuple в производный класс WorkoutSet.

public static implicit operator WorkoutSet( (TimeSpan rest, double repetition) data )
    => new WorkoutSet.BodyWeightReps((int)data.rest.TotalSeconds, data.repetition);

public static implicit operator WorkoutSet( (TimeSpan rest, double repetition, double weight ) data )
    => new WorkoutSet.WeightReps((int)data.rest.TotalSeconds, data.repetition, data.weight);

Применение

WorkoutSet bodyWeightReps = (TimeSpan.FromMinutes(0.5), repetition: 1.0d);
WorkoutSet weightReps = (TimeSpan.FromSeconds(42), repetition: 1.0d, weight: 2.0d);

Здесь вы можете найти рабочий пример: https://dotnetfiddle.net/P4rf2P

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

Похожие вопросы