Как создать экземпляр большого неизменяемого типа? - PullRequest
4 голосов
/ 25 июня 2010

У меня есть тип с примерно 40 свойствами (все типы значений), который представляет тип транзакции для моего бизнеса.Экземпляр этого класса соответствует строке в моей базе данных.Я хотел бы, чтобы мой класс оставался неизменным, так как он будет использоваться только для операций чтения, но я не уверен, как выполнить установку 40 свойств во время инициализации.

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

Ответы [ 6 ]

10 голосов
/ 25 июня 2010

Ваша проблема не столько в конструкторе с 40 аргументами, сколько в классе с 40 полями.

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

// Instead of this:
foo.EmailHeader
foo.EmailSubject
foo.Email...

// Do this:
foo.Email.Header
foo.Email.Subject

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

8 голосов
/ 25 июня 2010

Быстрая точка.Вы упомянули, что ваши сеттеры на объекте являются частными.Если это так, то ваш объект не является неизменным (иначе сеттеры не могли бы существовать).В лучшем случае ваш объект только для чтения.

Для истинно неизменного объекта нет другого выбора, кроме как заставить конструктор принять все значения, необходимые для инициализации объекта.Лучший способ уменьшить количество параметров в конструкторе - это сгруппировать значения в более крупные объекты, которые затем передаются в конструктор.Хотя я бы не стал этого делать, если только значения не связаны логически.

Если вашему неизменяемому типу действительно нужны 40 значений, а в остальном они не связаны, лучший способ - создать конструктор с 40 значениями.Это или дальше сломать большой неизменный объект.

4 голосов
/ 25 июня 2010

Мне нравится подход использования изменяемого объекта для создания экземпляра неизменяемого объекта; изменяемый объект предназначен только для аккуратной передачи опций. Одним из примеров этого в .NET Framework является ProcessStartInfo .

class XInfo {
  public int A;
  public int B;
}

class X {
  public X (XInfo i) {
    // you can transform the data/layout from i any way you need
    ..
  }
}

new X(new XInfo() {
  A = 42
})

Пока я молчу о «40 свойствах», я считаю, что описанный выше подход работает довольно хорошо. Дополнительным бонусом является XInfo, а внутренняя структура, используемая в X, может быть совершенно другой, если вы можете обеспечить нормальное отображение.

1 голос
/ 25 июня 2010

Если я скажу ваши слова "но я не уверен, как настроить 40 свойств во время инициализации.", Похоже, ваша проблема - это класс со слишком большим количеством полей / свойств.Кажется, не проблема сделать его неизменным, потому что вы уже знаете, как это сделать.

Я бы предложил (как и другие), Refactor и Extract Class.

0 голосов
/ 25 июня 2010

Я бы предложил поместить параметры в одну или несколько структур, и чтобы объект удерживал эти структуры.Вложенные объекты были бы возможны, но добавили бы больше накладных расходов, чем вложенные структуры.

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

0 голосов
/ 25 июня 2010

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

...