2010-03-16 4 views
5

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

Рассмотрим следующий пример:

Activity activity; 
activity.Start = "2010-01-01"; 
activity.Duration = "10 days"; // sets Finish property to "2010-01-10" 

Обратите внимание, что значения для даты и времени приведены только для ориентировочных целей.

Таким образом, использование сеттера для любого из свойств Start, Finish и Duration, следовательно, изменит другие свойства и, следовательно, не может считаться побочным эффектом. То же самое относится к экземплярам класса Rectangle, где установщик для X меняет значения Top и Bottom и так далее.

Вопрос в том, где бы вы нарисовали линию между использованием сеттеров, которые имеют побочные эффекты изменения значений логически связанных свойств и методы, которые в любом случае не могут быть более описательными. Например, определение метода, называемого SetDurationTo(Duration duration), также не отражает, что либо «Начало», либо «Готово» будут изменены.

ответ

8

Я думаю, что вы неправильно понимаете термин «побочный эффект», применительно к дизайну программы. Установка свойства - - побочный эффект, независимо от того, насколько или мало внутреннего состояния он изменяется, до тех пор, пока он меняет вид состояния. «Безцелевой сеттер» не был бы очень полезен.

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

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

Итак, отвечая на вопрос напрямую: Где я рисую линию? Нигде, пока метод/свойство действительно делает то, что подразумевает его название. Если установка Duration также изменила ActivityName, это может быть проблемой. Если он изменяет свойство Finish, это должно быть очевидно; это должно быть невозможно изменить Duration и иметь и Start, и Finish оставаться неизменным. Основная предпосылка ООП заключается в том, что объекты достаточно интеллектуальны, чтобы самостоятельно управлять этими операциями.

Если это беспокоит вас на концептуальном уровне, то у вас нет свойств мутатора - используйте неизменяемую структуру данных с свойствами только для чтения, где все необходимые аргументы предоставляются в конструкторе. Затем имеют две перегрузки, одну из которых занимает Start/Duration, а другая - Start/Finish. Или сделайте только одно из свойств, доступных для записи, допустим, Finish, чтобы он соответствовал Start - и затем сделать Duration только для чтения. Используйте соответствующую комбинацию изменяемых и неизменяемых свойств, чтобы гарантировать, что есть только один способ изменить определенное состояние.

В противном случае, не волнуйтесь об этом. Свойства (и методы) не должны иметь непреднамеренно или недокументированные побочные эффекты, но это касается единственного ориентира, который я бы использовал.

+0

Спасибо, это то, что я искал, и мне никогда не приходит в голову «побочный эффект» «свободный сеттер» на самом деле невозможен, так как он изменит состояние. И, как вы указали, CLR переведет метод в любом случае. – Martin

+0

Да, побочный эффект сеттера заключается в том, чтобы установить * переменную-член, к которой она относится *.Но дополнительным побочным эффектом является изменение * других * переменных-членов. –

+0

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

0

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

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

1

Лично я считаю, что имеет смысл иметь побочный эффект для поддержания согласованного состояния. Как вы сказали, имеет смысл изменить логически связанные значения. В каком-то смысле ожидается побочный эффект. Но важно сделать это ясно. То есть, должно быть очевидно, что задача, которую выполняет данный метод, имеет какой-то побочный эффект. Поэтому вместо SetDurationTo вы можете позвонить своей функции ChangeDurationTo, что означает, что происходит что-то еще. Вы также можете сделать это другим путем, используя функцию/метод, который регулирует продолжительность AdjustDurationTo и передает значение delta. Это поможет, если вы задокументируете функцию как побочный эффект.

Я думаю, что еще один способ взглянуть на это - увидеть, ожидается ли побочный эффект. В вашем примере Rectangle я бы ожидал, что он изменит значения top или bottom, чтобы поддерживать внутреннее согласованное состояние. Я не знаю, является ли это субъективным; мне кажется, это имеет смысл. Как всегда, я думаю, что документация побеждает. Если есть побочный эффект, запишите его очень хорошо. Предпочтительно по названию метода и через подтверждающую документацию.

-2

Я думаю, что это в основном вопрос здравого смысла.

В этом конкретном примере моя проблема заключается не столько в том, что у вас есть свойства, которые корректируют связанные свойства, а в том, что у вас есть свойства, принимающие строковые значения, которые вы затем внутренне обрабатываете в DateTime (или что-то еще) значения.

я предпочел бы увидеть что-то вроде этого:

Activity activity; 
activity.Start = DateTime.Parse("2010-01-01"); 
activity.Duration = Duration.Parse("10 days"); 

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

+0

Как я уже упоминал «Обратите внимание, что значения для даты и продолжительности показаны только для ориентировочных целей». Так что ваш комментарий действительно не затрагивает вопрос, но спасибо вам все равно ... Я знал, что кто-то укажет на это ;-) – Martin

1

Один из вариантов - сделать ваш класс неизменным и создать методы для создания и возврата новых экземпляров класса, которые имеют все соответствующие значения. Тогда нет никаких побочных эффектов или сеттеров. Подумайте о чем-то вроде DateTime, где вы можете назвать такие вещи, как AddDays и AddHours, которые возвратят новый экземпляр DateTime с внесенным изменением.

Смежные вопросы