Шаблон проектирования передачи данных структурированных данных в C #, почему бы не публичные переменные - PullRequest
0 голосов
/ 09 марта 2012

Как реализовать следующий шаблон "красиво": (с подсказкой arrrgh, почему я не могу просто использовать публичные переменные)

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

Итак, в прототипной версии моего приложения я набросал кучу классов совершенно публично:

public class AllData
{
    public IdentifyData identifyData;
    public FirmwareData firmwareData;
    public VersionData versionData;

    public TestData testData;
    public ServiceData serviceData;
    public ErrorLog errorLog;

    public AllData()
    {
        identifyData = new IdentifyData();
        versionData = new VersionData();
        firmwareData = new FirmwareData();
        testData = new TestData();
        serviceData = new ServiceData();
        errorLog = new ErrorLog();
    }

}

(...)

public class FirmwareData
{
    public DataStatus status;

    public int build;
    public int variant;

    public FirmwareData()
    {
        status = new DataStatus();
    }
}      

(Etc.)

Сейчас я делаю настоящую версию программного обеспечения и хочу все делать правильно, поэтому я начал распоряжаться всем. Тем не менее, я чувствую, что код делает удар, делая это. Это становится большим и уродливым, и выгода не очевидна в моем случае.

Я подумал об использовании структур вместо этого, но я действительно не хочу постоянно передавать все эти данные по значению. Кроме того, здесь и там есть несколько проверок дальности и здравомыслия.

Есть какие-нибудь подсказки о том, как правильно реализовать эту модель данных? (знайте, что я не очень опытен в ООП и C #)

Если возможно, я бы хотел, чтобы данные стали доступны только для чтения, когда они передаются классам потребителей, как можно это сделать?

Спасибо и всего наилучшего

Lars

Ответы [ 3 ]

1 голос
/ 09 марта 2012

Что бы вы не делали struct с. Особенно , если они изменчивы!

Просто используйте свойства - они обычно предпочтительнее полей (особенно если вы собираетесь использовать интерфейсные системы, которые, скажем, TypeDescriptor для получения информации о компонентах - Asp.Net MVC делает это).

Мое начальное правило заключается в том, что если он будет публичным или защищенным (в большинстве случаев), я буду использовать свойство. Если он защищенный или частный и неизменный , я рассмотрю использование поля только для чтения. Однако из этого правила всегда есть исключения, это всего лишь моя собственная отправная точка. Я редко когда-либо буду использовать открытое поле, за исключением вспомогательных классов для юнит-тестов.

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

Я бы использовал интерфейсы только для чтения:

public interface IMyData
{
   int Value { get; }
}

И тогда ваши классы можно будет читать / записывать, если они вам нужны:

public class MyData : IMyData
{
  public int Value { get; set; }
}

Интерфейс реализован - код, который использует и понимает MyData (т. Е. Ваш производитель) может писать в него, но код, который требуется только для чтения, использует только интерфейс. Использование такой абстракции также дает дополнительное преимущество, позволяя вашему потребительскому коду использовать ваши данные в любой форме. Например. Вы можете добавить реализации интерфейса к типам сущностей, сгенерированным EF, если вы выбрали ORM.

Имейте в виду, однако, что вы не всегда можете принудительно применять только чтение для всех - особенно если вы собираетесь использовать такие типы, как универсальные словари и т. Д.

Для объектов, которые действительно всегда должны быть неизменными после построения, используйте конструкторы и скройте сеттер. Итак, снова класс MyData:

 public int Value { get; private set; }     

 public MyData(int value){
   Value = value;
 }

Конечно, вы также можете использовать для этого поле только для чтения (но ни один из подходов на самом деле не помешает кому-то, кто действительно хочет изменить ваш объект, сделать это, поскольку оба подхода могут быть нивелированы отражением).

0 голосов
/ 04 декабря 2012

Если компоновка ваших данных будет фиксированной за все время и не требует каких-либо массивов, структура с открытыми полями может идеально подойти. Идея, что поля должны быть инкапсулированы в свойствах, хороша при применении к классам, но часто плоха при применении к структурам. По сути, структура представляет собой набор полей, связанных друг с другом клейкой лентой. Если struct1 и struct2 имеют один и тот же тип структуры, оператор struct1 = struct2 будет изменять struct1, перезаписывая все его поля значениями соответствующих полей в struct2. Ничто в определении типа структурного типа не может изменить это. Учитывая, что все поля структуры всегда публично подвергаются мутации посредством массового присваивания, может быть лучше иметь структуру, которая объявляет себя как набор переменных, склеенных с клейкой лентой, чем иметь структуру, которая притворяется чем-то другим.

Самая большая проблема с использованием структур с открытыми полями, по иронии судьбы, является их главным преимуществом: многие удобные способы использования структур с открытыми полями (особенно вложенных) не имеют удобных эквивалентов при использовании других типов данных. Если кто-то имеет массив какого-то вложенного типа структуры и хочет обновить внутренний элемент, можно сделать что-то вроде:

  TriangleList[index].Vertex1.X += 4;

и обновить часть элемента на месте. Если заменить массив на List<TriangleStruct>, код должен стать:

  var temp = TriangleList[index];
  temp.Vertex1.X += 4;
  TriangleList[index] = temp;

Все еще не так уж плохо. Предположим, однако, что необходимо изменить тип для поддержки произвольных многоугольников. Нельзя больше представлять тип со структурой открытого поля (если оно содержит массив, копирование структуры будет не копировать массив, а просто ссылку; изменение координаты в одной копии структуры, таким образом, изменит его для обоих, вероятно, приводя к неприятным ошибкам). Любой код для манипулирования структурой, который был основан на том, что он может использоваться как структура с открытым полем, должен быть полностью переписан.

Принимая решение о том, использовать ли структуру открытого поля или какой-либо другой тип данных, учитывайте степень, в которой будет полезно использовать удобные формы доступа, и вероятность того, что структура может измениться. Если способ использования объекта будет означать, что его семантика не может измениться без переписывания практически всего кода, который его использует, и было бы удобнее обращаться к нему как к структуре, а затем использовать открытую структуру поля. Нет причин делать ваш код более громоздким, чтобы приспособиться к будущим изменениям, которые никогда не произойдут, если YAGNI (вам это не нужно).

0 голосов
/ 09 марта 2012

Шаблоны проектирования здесь бесполезны, это касается того, как вы хотите организовать свои классы и их отношения.

Начните с объявления всех полей как private и выставьте в методах класса «что-то делать» с данными или в некоторых случаях их возвращайте, но старайтесь избегать того, чтобы клиенты могли напрямую обращаться к полям и, возможно, изменить им.

http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)

Это только отправная точка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...