Присвоение значения переменной в классе [duplicate]

Все объекты гарантированно имеют метод .equals(), поскольку Object содержит метод, .equals(), который возвращает логическое значение. Задача подкласса переопределять этот метод, если требуется дополнительное определение определения. Без него (т. Е. С помощью ==) только адреса памяти проверяются между двумя объектами для равенства. String переопределяет этот метод .equals() и вместо использования адреса памяти возвращает сравнение строк на уровне символа для равенства.

Ключевое замечание состоит в том, что строки хранятся в одном пуле, поэтому после создания строки он всегда хранится в программе по тому же адресу. Строки не меняются, они неизменяемы. Вот почему это плохая идея использовать регулярную конкатенацию строк, если у вас есть серьезное количество обработки строк. Вместо этого вы будете использовать предоставленные классы StringBuilder. Помните, что указатели на эту строку могут измениться, и если вам было интересно увидеть, были ли два указателя одинаковыми ==, это был бы прекрасный способ. Строки сами не делают.

1317
задан Tim Castelijns 6 December 2017 в 16:45
поделиться

31 ответ

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

Вот некоторые из причин, о которых я знаю:

  • Инкапсуляция поведения, связанная с получением или установкой свойства - это позволяет дополнительно функциональность (например, валидация), которая будет добавлена ​​позже.
  • Скрытие внутреннего представления свойства при экспонировании свойства с использованием альтернативного представления.
  • Изоляция вашего открытого интерфейса от изменения - разрешая публичный интерфейс остается постоянным, а реализация меняется, не затрагивая существующих потребителей.
  • Управление семантикой свойства управления жизненным циклом (memory) (удаление) - особенно важно в средах без управления (например, C ++ или Objective- C).
  • Предоставление точки перехвата отладки при изменении свойства во время выполнения - отладка, когда и когда свойство, измененное на конкретное значение, может быть довольно сложно без этого на некоторых языках.
  • Улучшенная совместимость с библиотеками, которые
  • Разрешить наследникам изменять семантику того, как свойство ведет себя и подвергается, переопределяя методы getter / setter.
  • g8]
  • Разрешить передачу геттера / сеттера в виде лямбда-выражений, а не значений.
  • Получатели и сеттеры могут разрешать разные уровни доступа - например, get может быть общедоступным, но набор может быть защищенный.
795
ответ дан Dennis Meng 15 August 2018 в 21:03
поделиться
  • 1
    +1. Просто добавьте: разрешение на ленивую загрузку. Разрешить копирование при записи. – NewbiZ 17 October 2009 в 00:41
  • 2
    @bjarkef: Я считаю, что методы доступа public вызывают дублирование кода и предоставляют информацию. Для сортировки (сериализации) не нужны общедоступные аксессоры. В некоторых языках (Java), public get accessors не могут иметь тип возвращаемого значения без нарушения зависимых классов. Более того, я считаю, что они противоречат принципам ОО. См. Также: stackoverflow.com/a/1462424/59087 – Dave Jarvis 5 March 2012 в 22:09
  • 3
    @sbi: Одна вещь, купленная с помощью средства настройки свойств, даже в хорошо продуманной структуре, - это возможность иметь объект, уведомляющий другого, когда изменяется свойство. – supercat 23 August 2012 в 22:48
  • 4
    @supercat: Однако я вообще не продвигаю публичные данные. Уведомление о других объектах также может быть сделано из реальных методов, обеспечивающих значительную абстракцию на простом контейнере данных с (более или менее) общедоступными полями данных. Вместо plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release(); я хочу сказать plane.takeOff(alt). Какие внутренние поля данных необходимо изменить, чтобы поместить плоскость в режим takingOff, это не моя проблема. И какие другие объекты (breaks) метод уведомляет, я тоже не хочу знать. – sbi 24 August 2012 в 10:35
  • 5
    @BenLee: Я действительно не знаю, как еще это сказать. & Quot; Аксессоры & Quot; является просто синонимом «getters / seters», и в моих первых двух комментариях я объяснил, почему это злоупотребление термином «ООП». Если вам нужно связаться с ним и напрямую манипулировать государством, это не является объектом в смысле ООП этого термина. – sbi 5 December 2012 в 10:22

Вы должны использовать геттеры и сеттеры, когда:

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

Так что это очень редко общий вопрос ОО; это вопрос, специфичный для языка, с разными ответами на разные языки (и различные варианты использования).


С точки зрения теории OO геттеры и сеттеры бесполезны. Интерфейс вашего класса - это то, что он делает, а не то, что его состояние. (Если нет, вы написали неправильный класс.) В очень простых случаях, когда то, что делает класс, просто, например, представляет точку в прямоугольных координатах, * атрибуты являются частью интерфейса; геттеры и сеттеры просто облака, что.

Путь другой: если вы считаете, что потребители вашего класса не должны даже знать, что у вас есть spam, а тем более быть способным изменить его волей-неволей, а затем дать им метод set_spam - это последнее, что вы хотите сделать.

* Даже для этого простого класса вы можете не обязательно хотите разрешить установку значений x и y. Если это действительно класс, не должны ли он иметь такие методы, как translate, rotate и т. Д.? Если это только класс, потому что ваш язык не имеет записей / structs / named tuples, тогда на самом деле это не вопрос OO ...


Но никто никогда не делает общий дизайн OO. Они выполняют дизайн и реализацию на определенном языке. И на некоторых языках геттеры и сеттеры далеки от бесполезности.

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

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

Что касается «что, если я хотите изменить мою реализацию позже? " вопрос (который повторяется несколько раз в разных формулировках как в вопросе OP, так и в принятом ответе): если это действительно чистое изменение реализации, и вы начали с атрибута, вы можете изменить его на свойство, не затрагивая интерфейс. Если, конечно, ваш язык не поддерживает это. Так что это действительно тот же случай снова.

Кроме того, важно следить за идиомами языка (или фреймворка), который вы используете. Если вы напишете красивый код стиля Ruby на C #, любой опытный разработчик C #, отличный от вас, будет иметь проблемы с его чтением, и это плохо. Некоторые языки имеют более сильные культуры вокруг своих конвенций, чем другие. - И не может быть совпадением, что Java и Python, которые находятся на противоположных концах спектра для того, как идиоматические геттеры, имеют две из самых сильных культур.

Помимо читателей, будут библиотеки и инструменты, которые ожидают, что вы последуете за конвенциями, и сделайте свою жизнь более сложной, если вы этого не сделаете. Виджеты Builder Interface Builder для чего-либо, кроме свойств ObjC, или с использованием некоторых Java-mocking-библиотек без геттеров, просто усложняют вашу жизнь. Если инструменты важны для вас, не сражайтесь с ними.

4
ответ дан abarnert 15 August 2018 в 21:03
поделиться

С точки зрения объектной ориентации обе альтернативы могут повредить поддержанию кода, ослабляя инкапсуляцию классов. Для обсуждения вы можете ознакомиться с этой замечательной статьей: http://typicalprogrammer.com/?p=23

4
ответ дан andrers52 15 August 2018 в 21:03
поделиться

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

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

int getVar() const { return var ; }

Итак, у вас есть:

doSomething( obj->getVar() ) ;

Вместо

doSomething( obj->var ) ;

Мало того, что getVar() визуально шумно, он дает иллюзию, что gettingVar() является каким-то более сложным процессом, чем он есть на самом деле. Как вы (как писатель класса) относитесь к неприкосновенности var, особенно сбивает с толку пользователь вашего класса, если у него есть сеттер passthru - тогда похоже, что вы поднимаете эти ворота, чтобы «защитить» то, что вы настаиваете (святость var), но даже вы уступаете защите var, не стоит того, чтобы кто-либо мог просто войти и set var на любую ценность, которую они хотят, без вы даже заглядываете в то, что они делают.

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

1) Начните со всех открытых элементов для базовых объектов с данными и поведением. Вот почему во всем моем «примерном» коде C ++ вы заметите, что я использую struct вместо class всюду.

2) Когда внутреннее поведение объекта для элемента данных становится достаточно сложным, ( например, ему нравится поддерживать внутренний std::list в каком-то порядке), записываются функции типа доступа. Поскольку я программирую сам по себе, я не всегда устанавливаю член private сразу, но где-то по эволюции класса член будет «продвигаться» до protected или private.

3) Классы, которые полностью очерчены и имеют строгие правила об их внутренностях (т.е. , они точно знают, что они делают, и вы не должны «трахаться» (технический термин) с его внутренности) присваиваются class, по умолчанию частные члены, и только избранным немногим членам разрешено быть public.

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

3
ответ дан bobobobo 15 August 2018 в 21:03
поделиться
  • 1
    «... четко определенный интерфейс, который вы не можете просто ввинтить с внутренними элементами & quot; и проверки в сеттерах. – Agi Hammerthief 18 December 2014 в 21:45

Начиная с 2 недель (месяцев, лет) с того момента, когда вы понимаете, что ваш сеттер должен делать больше, чем просто установить значение, вы также поймете, что свойство было использовано непосредственно в 238 других классах: -)

389
ответ дан ChssPly76 15 August 2018 в 21:03
поделиться
  • 1
    Я сижу и смотрю на приложение в 500 тыс. Строк, где он никогда не нужен. Тем не менее, если это понадобится один раз, это может привести к кошмару обслуживания. Достаточно хорош для галочки для меня. – Dean J 14 October 2009 в 19:24
  • 2
    Я могу только позавидовать вам и вашему приложению :-) Это говорит о том, что это действительно зависит от вашего программного стека. Например, Delphi (и C # - я думаю?) Позволяет вам определять свойства в качестве граждан первого класса, где они могут непосредственно читать и писать поле, но - если вам это нужно - делать это с помощью методов getter / setter. Mucho удобно. Java, увы, не означает - не говоря уже о стандарте javabeans, который заставляет вас использовать геттеры / сеттеры. – ChssPly76 14 October 2009 в 19:27
  • 3
    Хотя это действительно хорошая причина для использования аксессуаров, многие среды программирования и редакторы теперь предлагают поддержку для рефакторинга (либо в среде IDE, либо в виде бесплатных надстроек), что несколько снижает влияние проблемы. – LBushkin 14 October 2009 в 19:59
  • 4
    звучит как предварительная зрелая оптимизация – cmcginty 15 June 2012 в 22:31
  • 5
    Вопрос, который вам нужно задать, когда вы задаетесь вопросом, следует ли внедрять геттеры и сеттеры, это: Почему пользователям класса необходимо вообще обращаться к внутренним классам? Неважно, делают ли они это прямо или экранировано тонким псевдослоем - если пользователям необходимо получить доступ к деталям реализации, то это признак того, что класс не предлагает достаточно абстракции. См. Также этот комментарий . – sbi 23 August 2012 в 22:13

Я просто хотел бы бросить идею аннотации: @getter и @setter. С помощью @getter вы должны иметь возможность obj = class.field, но не class.field = obj. С @setter, наоборот. С @getter и @setter вы должны быть в состоянии сделать то и другое. Это позволит сохранить инкапсуляцию и сократить время, не вызывая тривиальные методы во время выполнения.

1
ответ дан fastcodejava 15 August 2018 в 21:03
поделиться
  • 1
    Он будет реализован во время выполнения с «тривиальными методами». На самом деле, вероятно, нетривиально. – Phil 29 October 2013 в 21:11
  • 2
    Сегодня это можно сделать с помощью препроцессора аннотации. – Thorbjørn Ravn Andersen 7 January 2018 в 20:56

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

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Выход:

0
0
4
3
ответ дан GeZo 15 August 2018 в 21:03
поделиться

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

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

Предположим, у нас есть этот простой класс:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Очень простой класс, в котором содержится количество жидкости в нем и что

Что происходит, когда я это делаю:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacity = 1000;

Ну, вы не ожидали, что это сработает, верно? Вы хотите, чтобы там была какая-то проверка здравомыслия. И что еще хуже, если я никогда не указывал максимальную емкость? О, дорогая, у нас есть проблема.

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

Мы получим что-то вроде:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
  public void setCapcityMl(int capacityMl);
}

Отлично! И теперь мы просто меняем Bottle на это:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;
  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  public void setCapcityMl(int capacityMl) {
    this.capacityMl = capacityMl;
    checkNotOverFlow();
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Я оставлю определение BottleOverflowException в качестве упражнения для читателя.

Теперь обратите внимание на то, насколько это более устойчиво. Теперь мы можем иметь дело с контейнером любого типа в нашем коде, принимая LiquidContainer вместо Bottle. И как эти бутылки справляются с такими вещами, все могут различаться. У вас могут быть бутылки, которые записывают свое состояние на диск, когда они меняются, или бутылки, которые сохраняются в базах данных SQL, или GNU знает, что еще.

И все это может иметь разные способы обработки различных крипов. Бутылка просто проверяет, и если она переполнена, она выдает исключение RuntimeException. Но это может быть неправильным. (Существует полезное обсуждение вопроса об обработке ошибок, но я делаю это очень просто здесь специально. Люди в комментариях, вероятно, укажут на недостатки этого упрощенного подхода.;))

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

Также есть и третье, что не все обратились: Getters и seters используют вызовы методов. Это означает, что они выглядят как обычные методы везде. Вместо того, чтобы иметь странный специфический синтаксис для DTO и т. Д., У вас есть одно и то же везде.

9
ответ дан Haakon Løtveit 15 August 2018 в 21:03
поделиться
  • 1
    Спасибо за первое полугодовое объяснение интерфейсов, которые я прочитал, без каких-либо ссылок на «удаленные элементы управления». или "автомобили" – djvs 10 February 2016 в 08:41
  • 2
    «У вас могут быть бутылки, которые записывают свое состояние на диск, когда они меняются, или бутылки, которые сохраняются в базах данных SQL». Я так сильно хмурился. Но в любом случае, хорошая идея представить его! – Xerus 18 October 2017 в 20:15

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

2
ответ дан Jason Baker 15 August 2018 в 21:03
поделиться
  • 1
    Я никогда не ожидал, что геттер или сеттер будут дорогостоящей операцией. В таких случаях лучше использовать завод: используйте все необходимые вам сеттеры, а затем вызовите дорогой метод execute или build. – Hubert Grzeskowiak 1 August 2016 в 09:54

Один из аспектов, которые я до сих пор пропустил в ответах: спецификация доступа:

  • для членов, у вас есть только одна спецификация доступа для установки и получения
  • для сеттеров и вы можете настроить его и определить отдельно
12
ответ дан jdehaan 15 August 2018 в 21:03
поделиться

В языках, которые не поддерживают «свойства» (C ++, Java) или требуют перекомпиляции клиентов при изменении полей в свойствах (C #), использование методов get / set легче модифицировать. Например, добавление логики проверки в метод setFoo не требует изменения общедоступного интерфейса класса.

В языках, поддерживающих «реальные» свойства (Python, Ruby, возможно, Smalltalk?), Нет смысла get / set.

9
ответ дан John Millikin 15 August 2018 в 21:03
поделиться
  • 1
    Re: C #. Если вы добавите функциональность в get / set, это не потребует перекомпиляции? – steamer25 14 October 2009 в 20:11
  • 2
    @ пароход25: извините, неправильно напечатано. Я имел в виду, что клиенты класса должны быть перекомпилированы. – John Millikin 14 October 2009 в 20:14
  • 3
    Добавление логики проверки к методу setFoo не требует изменения интерфейса класса на уровне языка , но он меняет фактический интерфейс , aka contract, поскольку он изменяет предпосылки. Зачем компилятору не рассматривать это как нарушение изменения , когда оно ? – R. Martinho Fernandes 26 September 2012 в 06:57
  • 4
    @ R.MartinhoFernandes, как можно исправить это "нарушение" проблема? Компилятор не может сказать, нарушает ли он или нет. Это всего лишь проблема, когда вы пишете библиотеки для других, но вы делаете это как универсальный zOMG, вот драконы! – Phil 29 October 2013 в 21:33
  • 5
    Требование перекомпиляции, как упоминалось в ответе, является одним из способов, которым компилятор может сообщить вам о возможном нарушении. И почти все, что я пишу, эффективно «библиотека для других», потому что я не работаю в одиночку. Я пишу код, который имеет интерфейсы, которые будут использовать другие люди в проекте. Какая разница? Черт, даже если я буду пользователем этих интерфейсов, почему я должен держать свой код для снижения стандартов качества? Мне не нравится работать с неприятными интерфейсами, даже если я их пишу. – R. Martinho Fernandes 30 October 2013 в 13:02

Ну, я просто хочу добавить, что даже если они иногда необходимы для инкапсуляции и безопасности ваших переменных / объектов, если мы хотим закодировать реальную объектно-ориентированную программу, тогда нам нужно STOP OVERUSING ACCESSORS , потому что иногда мы сильно зависим от них, когда это действительно не нужно, и это почти то же самое, что и мы ставим переменные public.

23
ответ дан Jorge Aguilar 15 August 2018 в 21:03
поделиться

Один из основных принципов дизайна OO: Encapsulation!

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

6
ответ дан Justin Niessner 15 August 2018 в 21:03
поделиться
  • 1
    Инкапсулирующие геттеры и сеттеры предлагают смехотворно тонкие. См. здесь . – sbi 23 August 2012 в 22:14
  • 2
    Если в вашем публичном интерфейсе указано, что «foo» имеет тип «T» и может быть установлен на что угодно, вы никогда не сможете его изменить. Вы не можете принять решение о типе «Y», и вы не можете вводить такие правила, как ограничения по размеру. Таким образом, если у вас есть общедоступный get / set, который ничего не делает / get, вы ничего не получаете, что публичное поле не будет предлагать и сделать его более громоздким в использовании. Если у вас есть ограничение, например, для объекта может быть установлено значение null, или значение должно быть в пределах диапазона, тогда да, будет использоваться метод публичного набора, но вы все еще представляете контракт от установки этого значения, t изменение – thecoshman 3 May 2013 в 11:17
  • 3
    Почему не может измениться контракт? – Phil 29 October 2013 в 22:04
  • 4
    Почему следует продолжать компиляцию, если контракты меняются? – R. Martinho Fernandes 30 October 2013 в 13:06

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

Скажите, что вы просматриваете сотни строк кода, и вы сталкиваетесь с этим:

person.name = "Joe";

Это красиво просто кусок кода, пока вы не поймете его сеттер. Теперь вы следуете за этим установщиком и обнаруживаете, что он также устанавливает person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName и вызывает person.update (), который отправляет запрос в базу данных и т. Д. О, это где произошла утечка памяти.

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

75
ответ дан Kai 15 August 2018 в 21:03
поделиться
  • 1
    Да. В настоящее время рефакторинг большой кодовой базы, и это был кошмар. Геттеры и сеттеры делают слишком много, включая вызов других очень занятых геттеров и сеттеров, которые в конечном итоге уменьшают удобочитаемость до нуля. Валидация - большая причина для использования аксессуаров, но использование их для выполнения гораздо большего, чем кажется, устраняет потенциальную выгоду. – Fadecomic 14 May 2012 в 20:56
  • 2
    Это аргумент против синтаксического сахара, а не против сеттеров вообще. – Phil 29 October 2013 в 21:02
  • 3
    Истинно и верно, но, кроме того, он указывает, почему почему индивидуальные сеттеры свойств открывают дверь для недействительных состояний, не имея абсолютно никакого средства для обеспечения целостности любого данного объекта, который позволяет абстракции протекать. – Darrell Teague 6 November 2013 в 17:26
  • 4
    «Это красиво просто кусок кода, пока вы не поймете его сеттер». - Эй, был ли исходный пост о Java или о C #? :) – Honza Zidek 13 April 2017 в 10:42
  • 5
    Я полностью согласен с читабельностью. Совершенно очевидно, что происходит, когда вызывается person.name = "Joe";. Там нет крутильной информации, подсветка синтаксиса показывает, что это поле, а рефакторинг проще (нет необходимости реорганизовывать два метода и поле). Во-вторых, все те израсходованные мозговые циклы, которые считаются «getIsValid ()», или он должен быть "isValid ()" и т. д. можно забыть. Я не могу придумать ни одного раза, когда я был спасен от ошибки с помощью геттера / сеттера. – Will 18 October 2017 в 10:41

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

Часто упоминаемое преимущество пар геттер / сеттер не является. Это утверждение, что вы можете изменить реализацию, и ваши клиенты не должны перекомпилироваться. Предположительно, сеттеры позволяют добавлять функции, такие как валидация, и ваши клиенты даже не должны знать об этом. Однако добавление валидации для сеттера является изменением его предварительных условий, нарушением предыдущего контракта, который был довольно простым: «вы можете положить что-нибудь здесь, и вы можете получить то же самое позже от геттера».

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

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

Этот же аргумент применим к другие предполагаемые преимущества этих сквозных пар getter / setter: если позже вы решите изменить установленное значение, вы нарушите контракт. Если вы переопределяете функциональные возможности по умолчанию в производном классе, в отличие от нескольких безвредных модификаций (таких как ведение журнала или другое не наблюдаемое поведение), вы нарушаете контракт базового класса. Это нарушение принципа Лисковской подстановочности, которое рассматривается как один из принципов ОО.

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

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Добавление пассивных пар getter / setter к такому класс не добавляет значения. Другие классы должны обеспечивать значимые операции, а не только операции, которые уже предоставляют поля. Вот как вы можете определять и поддерживать полезные инварианты.

Клиент: «Что я могу сделать с объектом этого класса?» Дизайнер: «Вы можете читать и писать несколько переменных». Клиент: «О ... круто, я думаю?»

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

309
ответ дан Lightness Races in Orbit 15 August 2018 в 21:03
поделиться
  • 1
    Отличный ответ (+1). Моя единственная критика заключается в том, что мне потребовалось несколько раз прочитать, как «валидация» в последнем абзаце отличались от "валидации" в первых немногих (которые вы выбросили в последнем случае, но продвинули в первом); корректировка формулировки может помочь в этом отношении. – Lightness Races in Orbit 6 July 2013 в 22:12
  • 2
    Это отличный ответ, но, увы, нынешняя эпоха забыла, что такое «скрытие информации». это то, для чего оно предназначено. Они никогда не читали о неизменности и в поисках большей гибкости, никогда не рисовали эту диаграмму состояния-перехода, которая определяла, что такое правовые состояния объекта, и, следовательно, что не было. – Darrell Teague 6 November 2013 в 16:58
  • 3
    Главное наблюдение заключается в том, что геттеры гораздо полезнее, чем сеттеры. Геттер может возвращать вычисленное значение или кэшированное вычисленное значение. Весь сеттер может выполнить некоторую проверку и изменить поле private. Если у класса нет сеттеров, легко сделать его неизменным. – Raedwald 12 December 2014 в 09:38
  • 4
    Er, я думаю, вы не знаете, что такое инвариант класса. Если это нетривиальная структура, это в значительной степени означает, что у нее есть инварианты для поддержки, и один просто не может ее проектировать без этих соображений. «Была ошибка, один член был обновлен неправильно». также в значительной степени читается как «Обновление члена нарушает инварианты класса». Хорошо продуманный класс не позволяет клиентскому коду нарушать его инварианты. – R. Martinho Fernandes 5 August 2015 в 08:25
  • 5
    +1 для «немых владельцев данных» должны выглядеть как немые держатели данных. К сожалению, каждый, похоже, все вокруг вокруг немых держателей данных создает все вокруг, и многие фреймворки даже требуют этого ... – Joeri Hendrickx 29 August 2016 в 06:53

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

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

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

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

15
ответ дан Mohamed 15 August 2018 в 21:03
поделиться

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

Например, к переменной, которой вы никогда не предназначались для использования за пределами класса, можно было получить доступ, даже прямо через доступ к цепочке переменных переменных ( т.е. object.item.origin.x).

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

1
ответ дан MongooseLover 15 August 2018 в 21:03
поделиться
  • 1
    Ярким примером этого является установка значения одного атрибута для одного или нескольких других значений атрибутов. Тривиальный пример: скажем, вы храните радиус круга. Использование circ.set_radius () `на самом деле не достигает чего-либо, задающего радиус непосредственно через circ.radius, нет. Однако get_diameter (), get_circumference () и get_area () могут выполнять вычисления на основе радиуса. Без геттеров вам приходится самостоятельно выполнять вычисления и проверять, что вы их правильно. – Agi Hammerthief 18 December 2014 в 21:37

Зависит от вашего языка. Вы отметили эту «объектно-ориентированную», а не «Java», поэтому я хотел бы указать, что ответ ChssPly76 зависит от языка. В Python, например, нет причин использовать геттеры и сеттеры. Если вам нужно изменить поведение, вы можете использовать свойство, которое обертывает getter и setter вокруг доступа к базовому атрибуту. Что-то вроде этого:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)
28
ответ дан Ned Batchelder 15 August 2018 в 21:03
поделиться
  • 1
    Да, я сказал в комментариях ниже моего ответа. Java не является единственным языком для использования геттеров / сеттеров в качестве костыля, так же как Python - не единственный язык, способный определять свойства. Однако основной момент остается - «свойство» это не то же самое «публичное поле». – ChssPly76 14 October 2009 в 19:40
  • 2
    @jcd - совсем нет. Вы определяете свой & quot; интерфейс & quot; (публичный API будет лучшим термином здесь), подвергая свои публичные поля. Как только это будет сделано, нет возврата. Свойства не являются полями, потому что они предоставляют вам механизм для перехвата попыток доступа к полям (путем маршрутизации их методам, если они определены); это, однако, не что иное, как синтаксис сахара по методам геттера / сеттера. Это чрезвычайно удобно, но это не изменяет основную парадигму - разоблачение полей без контроля над доступом к ним нарушает принцип инкапсуляции. – ChssPly76 15 October 2009 в 22:09
  • 3
    @ ChssPly76-я не согласен. У меня такой же контроль, как если бы они были свойствами, потому что я могу сделать их свойствами всякий раз, когда мне нужно. Нет никакой разницы между свойством, которое использует шаблонные геттеры и сеттеры, и атрибутом raw, за исключением того, что исходный атрибут выполняется быстрее, потому что он использует основной язык, а не вызывающий метод. Функционально они идентичны. Единственный способ инкапсуляции может быть нарушен, если вы думаете, что скобки (obj.set_attr('foo')) по своей природе превосходят знаки равенства (obj.attr = 'foo'). Общественный доступ - это общедоступный доступ. – jcdyer 16 October 2009 в 16:27
  • 4
    @jcdyer так же управляет да, но не так много читаемости, другие часто ошибочно предполагают, что obj.attr = 'foo' просто устанавливает переменную, не делая ничего другого – Timo Huovinen 10 August 2013 в 10:49
  • 5
    @TimoHuovinen Как это отличается от пользователя в Java, предполагая, что obj.setAttr('foo') "просто устанавливает переменную без каких-либо других событий"? Если это общедоступные методы, то это общедоступный метод. Если вы используете его для достижения какого-либо побочного эффекта, и он является общедоступным, то вам лучше быть в состоянии рассчитывать на все, что работает , как если бы произошел только тот предполагаемый побочный эффект all i> другие детали реализации и другие побочные эффекты, использование ресурсов, что угодно, скрытые от проблем пользователя). Это абсолютно не отличается от Python. Синтаксис Python для достижения эффекта просто проще. – ely 17 October 2014 в 15:00

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

Я провел небольшой тест производительности. Я написал класс «NumberHolder», который, ну, имеет целое число. Вы можете прочитать это Integer с помощью метода getter anInstance.getNumber() или путем прямого доступа к номеру с помощью anInstance.number. Моя программа читает номер 1,000,000,000 раз, в обоих направлениях. Этот процесс повторяется пять раз и время печатается. У меня есть следующий результат:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(время 1 - это прямой путь, время 2 - геттер)

Вы видите, что геттер (почти) всегда бит быстрее. Затем я пробовал с различным количеством циклов. Вместо 1 миллиона я использовал 10 миллионов и 0,1 миллиона. Результаты:

10 миллионов циклов:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

С 10 миллионами циклов времена почти одинаковы. Вот 100 тысяч (0,1 миллиона) циклов:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

Также с разным количеством циклов, геттер немного быстрее обычного. Надеюсь, это помогло вам.

22
ответ дан Nick A 15 August 2018 в 21:03
поделиться
  • 1
    Есть "примечательный" накладные расходы, имеющие вызов функции для доступа к памяти вместо простой загрузки адреса объекта и добавления смещения для доступа к членам. Скорее всего, виртуальная машина оптимизировала ваш геттер. Несмотря на это, упомянутые накладные расходы не должны терять все преимущества геттеров / сеттеров. – Alex 6 September 2016 в 17:28

Кроме того, это означает «будущий» класс. В частности, переход с поля на свойство - это разрыв ABI, поэтому, если вы позже решите, что вам нужна больше логики, чем просто «установить / получить поле», тогда вам нужно сломать ABI, что, конечно, создает проблемы для чего-либо else уже скомпилирован против вашего класса.

1
ответ дан Pete 15 August 2018 в 21:03
поделиться
  • 1
    Я полагаю, что изменение поведения геттера или сеттера не является изменением. & Lt; / сарказм & GT; – R. Martinho Fernandes 26 September 2012 в 06:54
  • 2
    @ R.MartinhoFernandes не всегда должен быть. TBYS – Phil 29 October 2013 в 21:10

Существует много причин. Мой любимый - когда вам нужно изменить поведение или отрегулировать то, что вы можете установить для переменной. Например, скажем, у вас был метод setSpeed ​​(int speed). Но вы хотите, чтобы вы могли установить максимальную скорость 100. Вы бы сделали что-то вроде:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Теперь, что, если EVERYWHERE в вашем коде вы использовали публичное поле, а затем вы поняли, что вам нужно выше требования? Получите удовольствие, охотясь за каждым использованием публичного поля, а не просто изменяя свой сеттер.

Мои 2 цента:)

43
ответ дан Peter D 15 August 2018 в 21:03
поделиться
  • 1
    Охота на любое использование публичного поля не должна быть такой сложной. Сделайте его приватным и пусть компилятор найдет их. – Nathan Fellman 14 October 2009 в 19:57
  • 2
    это, конечно, правда, но зачем делать его труднее, чем это было предназначено. Метод get / set по-прежнему является лучшим ответом. – Hardryv 14 October 2009 в 20:05
  • 3
    @Nathan: Поиск других способов использования не является проблемой. Изменение всех. – Graeme Perrow 7 November 2009 в 23:09
  • 4
    @GraemePerrow, чтобы изменить их все, является преимуществом, а не проблемой :( Что, если бы у вас был код, который предположил бы, что скорость может быть выше 100 (потому что, как вы знаете, до того, как вы нарушили контракт, это могло бы!) (while(speed < 200) { do_something(); accelerate(); }) – R. Martinho Fernandes 30 October 2013 в 13:12
  • 5
    Это ОЧЕНЬ плохой пример! Кто-то должен позвонить: myCar.setSpeed(157); и после нескольких строк speed = myCar.getSpeed(); И теперь ... Желаю вам удачной отладки, пытаясь понять, почему speed==100, когда это должно быть 157 – Piotr Aleksander Chmielowski 23 February 2016 в 13:24

Геттеры и сеттеры используются для реализации двух основных аспектов объектно-ориентированного программирования, которые:

  1. Абстракция
  2. Инкапсуляция

Предположим, у нас есть класс Employee:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Здесь детали реализации полного имени скрыты от пользователя и недоступны непосредственно пользователю, в отличие от общедоступного атрибута.

2
ответ дан Pritam Banerjee 15 August 2018 в 21:03
поделиться
  • 1
    Для меня, имеющего массу геттеров и сеттеров, которые ничего не делают, бесполезно. getFullName является исключением, потому что он делает что-то еще. Имея только три переменные public, то сохранение getFullName сделает программу более легкой для чтения, но все-таки будет скрыто это полное имя. Вообще я полностью в порядке с геттерами и сеттерами, если a. они делают что-то уникальное и / или b. у вас есть только один, да, у вас может быть публичный финал, и все, кроме нон – FacelessTiger 14 December 2016 в 02:06
  • 2
    Преимущество в этом состоит в том, что вы можете изменить внутренности класса без изменения интерфейса. Скажем, вместо трех свойств у вас был один - массив строк. Если вы используете геттеры и сеттеры, вы можете внести это изменение, а затем обновить геттер / сеттеры, чтобы знать, что имена [0] - это имя, имена [1] являются средними и т. Д. Но если вы просто использовали общедоступные свойства , вам также необходимо будет изменить каждый доступный Employee Employee, поскольку свойство firstName, которое они использовали, больше не существует. – Andrew Hows 8 December 2017 в 01:42

Мы используем геттеры и сеттеры:

  • для повторного использования
  • для выполнения проверки на более поздних этапах программирования

Геттер и сеттер методы - это публичные интерфейсы для доступа к частным членам класса.


Мантрация инкапсуляции

Мантра инкапсуляции должна делать частные и общедоступные поля.

Методы Getter: Мы можем получить доступ к закрытым переменным.

Setter Methods: Мы можем изменить частные поля.

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

  • ;
  • более безопасным; и
  • быстрее.

В любом месте можно использовать значение, которое возвращает это значение. Вместо:

int x = 1000 - 500

используйте

int x = 1000 - class_name.getValue();

В терминах непрофессионала

Representation of "Person" class [/g5]

Предположим, нам нужно сохранить детали этого Person. Это Person имеет поля name, age и sex. Для этого необходимо создать методы для name, age и sex. Теперь, если нам нужно создать другого человека, необходимо снова создать методы для name, age, sex.

Вместо этого мы можем создать компонент class(Person) с методами геттера и сеттера. Поэтому завтра мы можем просто создавать объекты этого Bean class(Person class), когда нам нужно добавить нового человека (см. Рисунок). Таким образом, мы повторно используем поля и методы класса bean, что намного лучше.

14
ответ дан Qantas 94 Heavy 15 August 2018 в 21:03
поделиться

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

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

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

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

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }
14
ответ дан quillbreaker 15 August 2018 в 21:03
поделиться

Одним из относительно современных преимуществ getters / seters является то, что упрощает просмотр кода в тегах (индексированных) редакторах кода. Например. Если вы хотите узнать, кто устанавливает член, вы можете открыть иерархию вызовов сеттера.

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

2
ответ дан Rakesh Singh 15 August 2018 в 21:03
поделиться

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

  1. Когда вы понимаете, что вам нужно сделать больше, чем просто установить и получить значение, вы можете просто сделать полевое частное, которое сразу сообщит вам, где вы напрямую обращались к нему.
  2. Любая проверка, которую вы выполняете, может быть только контекстной, что редко бывает на практике.
  3. Вы может изменить установленное значение - это абсолютный кошмар, когда вызывающий абонент передает вам значение, которое они [shock horror] хотят, чтобы вы сохранили AS IS.
  4. Вы можете скрыть внутреннее представление - фантастическое, так что вы «Убедитесь, что все эти операции симметричны правильно?
  5. Вы изолировали свой публичный интерфейс от изменений под листами - если вы разрабатывали интерфейс и не были уверены, что прямой доступ к чему-то был в порядке , тогда вы должны были продолжать проектирование.
  6. Некоторые библиотеки ожидают этого, но не так много - отражение, сериализация, макет объектов все отлично работает с pu blic fields.
  7. Наследуя этот класс, вы можете переопределить функции по умолчанию - другими словами, вы можете ДЕЙСТВИТЕЛЬНО путать вызывающих, не только скрывая реализацию, но и делая ее непоследовательной.

Последние три я ухожу (N / A или D / C) ...

21
ответ дан StackedCrooked 15 August 2018 в 21:03
поделиться
  • 1
    Я думаю, что решающим аргументом является то, что ", если вы разрабатывали интерфейс и не были уверены, что прямой доступ к чему-то был в порядке, тогда вы должны были продолжать проектирование. & Quot; Это самый важный проблема с геттерами / сеттерами: они сводят класс к простому контейнеру (более или менее) публичных полей. Однако в real OOP объект больше, чем контейнер полей данных. Он инкапсулирует состояние и алгоритмы для управления этим состоянием. Что важно в этом заявлении, так это то, что состояние должно быть инкапсулировано и должно управляться только алгоритмами, предоставляемыми объектом. – sbi 24 August 2012 в 10:29

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

Есть некоторые преимущества использования методов getter и setter, таких как возможность позволить вам создавать элементы со сложными функциями, которые вы может получить доступ к таким свойствам. Они также позволяют создавать свойства только для чтения и только для записи.

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

Когда вы пишете классы, вам всегда рекомендуется делать как можно больше ваших переменных экземпляра частным и соответственно добавлять методы getter и setter. Это происходит потому, что есть несколько раз, когда вы не можете позволить пользователям изменять определенные переменные в ваших классах. Например, если у вас есть частный статический метод, который отслеживает количество экземпляров, созданных для определенного класса, вы не хотите, чтобы пользователь модифицировал этот счетчик с помощью кода. Только инструкция конструктора должна увеличивать эту переменную всякий раз, когда она вызывается. В этой ситуации вы можете создать переменную частного экземпляра и разрешить метод getter только для переменной счетчика, что означает, что пользователи могут извлекать текущее значение только с помощью метода getter, и они не смогут устанавливать новые значения используя метод setter. Создание геттера без сеттера - это простой способ сделать определенные переменные в вашем классе доступными только для чтения.

3
ответ дан Sumit Singh 15 August 2018 в 21:03
поделиться

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

Например, если foo был общедоступным, я мог бы легко установить его на null, а затем кто-то попытался бы позвонить метод на объекте. Но его больше нет! С помощью метода setFoo я мог убедиться, что foo никогда не был установлен в null.

Аксессоры и мутаторы также допускают инкапсуляцию - если вы не должны видеть значение после его установки (возможно, он установлен в конструкторе, а затем используется методами, но никогда не должен быть изменен), он никогда не будет замечен кем-либо. Но если вы можете разрешить другим классам просматривать или изменять его, вы можете предоставить соответствующий аксессуар и / или мутатор.

36
ответ дан Thomas Owens 15 August 2018 в 21:03
поделиться

Я потратил немало времени, думая об этом для случая Java, и я считаю, что настоящими причинами являются:

  1. Код для интерфейса, а не реализация
  2. Интерфейсы только указать методы, а не поля

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

Эти методы - позорный геттер и сеттер ....

14
ответ дан Thorbjørn Ravn Andersen 15 August 2018 в 21:03
поделиться
  • 1
    Хорошо, второй вопрос; в случае, когда это проект, в котором вы не экспортируете источник никому, и у вас есть полный контроль над источником ... вы получаете что-либо с помощью геттеров и сеттеров? – Dean J 9 November 2009 в 16:22
  • 2
    В любом нетривиальном Java-проекте вам нужно кодировать интерфейсы, чтобы сделать вещи управляемыми и проверяемыми (подумайте о макетах и ​​объектах прокси). Если вы используете интерфейсы, вам нужны геттеры и сеттеры. – Thorbjørn Ravn Andersen 9 November 2009 в 19:13

В чистом объектно-ориентированном мире геттеры и сеттеры - страшный анти-шаблон. Прочтите эту статью: Getters / Setters. Зло. Период . В двух словах они поощряют программистов думать об объектах как о структурах данных, и этот тип мышления является чисто процедурным (например, в COBOL или C). На объектно-ориентированном языке отсутствуют структуры данных, но только объекты, которые выставляют поведение (не атрибуты / свойства!) [/ ​​G2]

. Вы можете найти больше о них в разделе 3.5 из Элегантные объекты (моя книга об объектно-ориентированном программировании).

43
ответ дан yegor256 15 August 2018 в 21:03
поделиться
  • 1
    Геттеры и сеттеры предлагают модель анемичного домена. – Raedwald 12 December 2014 в 09:31
  • 2
    Интересная точка зрения. Но в большинстве программных контекстов нам нужны структуры данных. Взяв связанную статью «Dog & quot; пример. Да, вы не можете изменить вес реальной собаки, установив атрибут ... но new Dog() не является собакой. Это объект, который содержит информацию о собаке. И для этого использования, естественно, можно исправить неправильно записанный вес. – Stephen C 1 July 2016 в 07:29
  • 3
    @StephenC - это именно то, как обучают нас процессуальные языки. Объектное мышление абсолютно противоположно. Объект не сохраняет информацию о собаке. Объект является собакой . Эта книга может помочь: Элегантные объекты – yegor256 1 July 2016 в 22:41
  • 4
    Ну, я сказал вам, что most полезным программам не нужно моделировать / имитировать объекты реального мира. ИМО, это вообще не о языках программирования. Речь идет о том, для чего мы пишем программы. – Stephen C 2 July 2016 в 00:34
  • 5
    Реальный мир или нет, его закон совершенно прав. Если то, что у вас есть, действительно является «Структурой». и вам не нужно писать код, который ссылается на него по имени, помещает его в хэш-таблицу или другую структуру данных. Если вам нужно написать код для него, тогда поместите его как член класса и поместите код, который управляет этой переменной в том же классе, и опустите setter & amp; добытчик. PS. хотя я в основном разделяю точку зрения Егора, я пришел к убеждению, что аннотированные бобы без кода - это несколько полезные структуры данных - также иногда нужны геттеры, сеттеры никогда не должны существовать. – Bill K 1 May 2017 в 16:51
Другие вопросы по тегам:

Похожие вопросы: