2010-06-24 2 views
4

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

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

+1

Можете ли вы просто иметь ctor, который проходит в строке (однако у вас есть это, DataRow, или хеш-таблица, или linq-объект или что-то еще), и он снимает значения столбца и устанавливает каждый из них? (this.Col1 = foo.Col1, repeat)? –

+0

Мне обычно не нравится добавлять заводские функции, которые принимают определенные инициализаторы. Он может отлично работать для одного решения для хранения данных, но если вам когда-либо придется переносить другое решение для хранения данных, это создает много дополнительных функций и бесполезных функций для ваших типов. –

ответ

8

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

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

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

+0

40 значений ... моя голова взорвется. – 2010-06-24 20:50:46

+0

@pst, я видел это раньше, но чаще всего в сгенерированном коде. – JaredPar

+0

Именованные параметры могут сделать это немного менее болезненным. Конечно, вам нужно их правильно назвать. – ChaosPandion

10

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

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

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

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

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

+0

Я определенно согласен с этим. Класс, в котором хранится 40 данных, которые нельзя поместить в список или другой контейнер? Плохой дизайн. – Puppy

+0

Thats отличная идея. –

+0

+1. Согласен. 40 атрибутов, которые нельзя сгруппировать в другие объекты, действительно пахнут. – bloparod

4

Мне нравится подход к использованию изменяемого объекта для создания объекта неизменяемости; измененный объект предназначен только для аккуратного прохождения опций. Одним из примеров этого в платформе .NET является 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, может быть совершенно иной, если вы можете обеспечить разумное сопоставление.

+0

Это шаблон Builder. 'StringBuilder' и' XmlReaderSettings' являются еще двумя примерами. –

+0

@ Stephen - Строитель patten может немного раздражать, но он работает. – ChaosPandion

0

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

+0

Я бы добавил +1, за исключением того, что IFreezable - это огромный интерфейс для реализации. Это было бы излишним. Вероятно, ему было бы лучше создать гораздо меньший, более простой интерфейс IFreezable и придерживаться этого. – Phil

1

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

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

0

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

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