Слишком много объектов, слишком «глубокая» структура классов?

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

Основная идея заключается в том, что пользователю нужно только создать экземпляр большого базового класса, а затем построить его с помощью других типов объектов.

Вот некоторые из свойств базового класса:

public class ConfigurationSheet
{
    public List<MainStep> MainSteps { get; set; }
    public List<SequenceStep> SequenceSteps { get; set; }
    public List<SubSequenceStep> SubSequenceSteps { get; set; }
    public List<ConfigurationRow> ConfigurationRows { get; set; }

    public List<Tag> PLCTags
    {
        get { return ConfigurationRows.Select(x => x.PLCTag).ToList(); }
    }
}

Эти типы все мои и поставляются с библиотекой, например, ConfigurationRow -объект выглядит следующим образом:

public class ConfigurationRow
{
    public Tag PLCTag { get; set; }
    public Dictionary<int, StepArguments> Arguments { get; set; }
}

И так продолжается. Вот объект StepArguments:

public class StepArguments
{
    public Configurations Configurations { get; set; }
    public Calculations Calculations { get; set; }
}

Объект Configurations фактически идет еще на два шага глубже.

Это может привести к появлению такого кода:

if(sheet.SequenceStep[0].DefaultConfigurations.Tolerances.SetPoint > 0)
    sheet.ConfigurationRows[1].Arguments[120].Configurations.Tolerances.HighLimit = 200;

И это не кажется мне правильным. Должен ли я сломать некоторые из моих объектов и поместить свойства в более крупные классы, или мне нужно создать ярлыки /методы /индексаторы, или я, может быть, просто слишком остро реагирую?

Я думаю, может быть, что-то вроде этого:

public class StepArguments
{
    public Configurations Configurations { get; set; }
    public Calculations Calculations { get; set; }
    public double HighLimit { get { return Configurations.Tolerances.HighLimit; } }
}

Что позволит это:

if(sheet.SequenceStep[0].SetPoint > 0)
    sheet.ConfigurationRows[1].Arguments[120].HighLimit = 200;

В то время как это сделает более четкий код, это также разрушит цель использования класса Configurations.

11 голосов | спросил Hjalmar Z 25 J000000Friday14 2014, 12:29:31

2 ответа


7

Я думаю, что вы должны обязательно сохранить структуру класса как можно ближе к фактической структуре данных. Так, например, если ваш MainStep "содержит" SequenceStep, вы должны отразить это в своем коде, используя агрегацию:

class MainStep
{
    public List<SequenceStep> SequenceSteps { get; set; }
    .....
}

и т.д ...

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

public static IEnumerable<SequenceStep> GetSequenceSteps(this ConfigurationSheet sheet)
{
    foreach(var main in sheet.MainSteps)
    {
        foreach(var sub in main.SequenceSteps)
        {
            yield return sub;
        }
    }
}

(или вы можете использовать Linq).

Я думаю, что строка sheet.ConfigurationRows[1].Arguments[120].Configurations.Tolerances.HighLimit в порядке, если она отражает фактическую структуру данных. Его определенно не самая сложная вещь в мире, далека от нее (отображения для сложных баз данных часто имеют еще больше уровней агрегации :)). Этого мало, что можно сделать.

  1. Если вы контролируете свои данные, вы можете попытаться изменить его формат на более простой.
  2. Вы также можете попытаться переместить логику на более низкий уровень, где это возможно. Поэтому он будет выглядеть как row.Arguments[120].Configurations.Tolerances.HighLimit. Его трудно сказать точный рефакторинг, не видя более крупную картину. Использование «ярлыков» для общедоступных полей также прекрасное, если вы не переусердствовали. Используйте методы расширения для этого, где это возможно, чтобы структура классов оставалась ясной.
  3. Вы можете использовать более короткие имена. Вам действительно нужно иметь ConfigurationSheet.ConfigurationRow, например? Разве это не ConfigurationSheet.Row как читаемый?
  4. Также, если Arguments является эквивалентом отдельных «ячеек», то использование индексаторов имеет смысл: sheet[1][120]
ответил Nikita B 25 J000000Friday14 2014, 13:14:58
3

Вот мои мысли об этом. К сожалению, это немного расплывчато, но я буду продолжать думать об этом.

  • Поддержание работоспособности. Целевые должности такого рода могут часто меняться. Прямо сейчас у вас есть пара уровней под корнем, с которыми можно легко справиться с тем, что вы написали. . Вы должны судить, будет ли босс возвращаться к вам и просить что-то более сложное. На самом деле это бит, который я нахожу самым сложным в программировании. Вы не хотите тратить время, но вы можете тратить время, строя вещи, а также не создавая их.

  • Сложность: предположим, что он становится более сложным, и вы делаете Step [i] .substep [j] .substep [k] .substep [l] ... и т. д. В какой-то момент это будет запутанной и трудно отлаживаемой. Подумайте о какой-то иерархической структуре, которая эффективно превращает код в двухэтапный процесс: проверьте для детей или заполните информацию. Это, вероятно, будет выглядеть как таблица базы данных некоторого типа (или LINQ, если вам нравится) с некоторыми столбцами, определяющими, где находится данный узел, то есть таблица, представляющая дерево (может быть, идея найти некоторый ранее существующий древовидный код) .

  • Модели и значения: подумайте о том, почему у вас несколько слоев. Если каждый слой отличается от следующего и имеет четкую цель, то на самом деле то, что вы написали, в порядке. Потому что легче отлаживать что-то, когда вы знаете, что он должен делать. По правде говоря, это еще одна часть неопределенного совета.

ответил Carlos 25 J000000Friday14 2014, 13:16:44

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132