Подтвердить что ты не робот

Очень распространенная картина С#, которая нарушает очень фундаментальный принцип ООП

Вот очень простой вопрос, о котором я все еще очень беспокоюсь:

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

public class EncapsulationViolator
{
  private object abuseMe;

  public object AbuseMe 
  {
    get { return abuseMe; }
  }
}

Изменить Случай, который я рассматривал, - это

EncapsulationViolator ev = new EncapsulationViolator();

object o = ev.AbuseMe;

o.SetValue(newValue);

Теперь состояние ev имеет изменение через транзитивность, потому что состояние его члена abuseMe изменилось.

В контексте DDD это не нормально, если объект является агрегированным корнем. Я цитирую

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

[Проект, управляемый доменами, Эрик Эванс]

... сеттеры schmetters...

4b9b3361

Ответ 1

Вы объединяете термин "ссылка" на С++ с тем, что С# передает объекты по значению (их ссылки).

В этом случае вызывающий элемент getter AbuseMe не может поменять приватное поле AbuseMe. Таким образом, нет никакого нарушения инкапсуляции.

EncapsulationViolator x = new EncapsulationViolator();
object y = x.AbuseMe;
y = 17; // I have not changed x.AbuseMe

Debug.Assert(y != x.AbuseMe); // Passes!

Кроме того, свойства getters и seters позволяют правильно инкапсулировать частные поля и функционально идентичны реализации этих методов (на самом деле они реализованы как методы компилятором).

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

class X
{
    private int[] amazing = new int[10];

    public int[] Amazing { get { return this.amazing; } }
}

X a = new X();
int[] x = a.Amazing;
int[] y = a.Amazing;

x[2] = 9;
Debug.Assert(x[2] != y[2]); // Fails!

Ответ 2

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

Если это изменяемый объект, вы можете изменить содержимое объекта вне класса, но вы не можете заменить сам объект.

Если объект не может быть изменен извне класса, то он должен вернуть неизменяемую версию объекта.

Образец может разорвать инкапсуляцию, если вы сделаете это неправильно, но правильно выполнил инкапсуляцию.

Ответ 3

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

Точка заключается в том, что класс решает, что он позволяет пользователям делать с этим членом (get/set или оба и их видимость), он может выполнять проверку и предотвращать недопустимые значения, и пользователям не нужно знать откуда эта ценность.

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

Ответ 4

Это просто синтаксический сахар. Это не отличается от методов Java getXXX и setXXX.

Ответ 5

Точка геттера и сеттера специально предназначена для обеспечения инкапсуляции. Все дело в том, что вы не предоставляете доступ непосредственно к объекту, а заставляете его обращаться с помощью функции, которую вы определяете. Геттеры и сеттеры. Инкапсуляция. Если вы решили просто вернуть объект, хорошо, что ваш бизнес, но вы не разрешаете прямой доступ, не попав в геттер.

Прочтите это: http://en.wikipedia.org/wiki/Mutator_method

Ответ 6

ИМО - здесь слишком много ответов - это пропаганда геттеров/сеттеров. Getters/seters отлично подходят для процедурного кода, вы либо выполняете некоторые вычисления, либо устанавливаете результат, либо получаете значение и принимаете какое-то решение.

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

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