Когда имеет смысл использовать открытое поле? - PullRequest
19 голосов
/ 09 августа 2011

Это вопрос, который у меня возник некоторое время:

Когда имеет смысл публично выставлять поле таким образом?

public class SomeClass()
{
   public int backing;
}

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

В Java и C # передовой практикой уже давно является использование методов получения / установки или свойств для доступа к полям.

public class SomeClass()
{
   private int backing;

   public int getBacking()
   {
      return backing;
   }

   public void setBacking(int v)
   {
      backing = v;
   }
}

C # превратил это в довольно простой синтаксис с автоматическими свойствами:

public class SomeClass()
{
   public int Backing { get; set; }
}

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

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

public class SomeClass()
{
   public int backing;   // The same as public int backing { get; set; }
}

Для свойства, которое не делает ничего, кроме переноса базового поля, я почти уверен, что JIT оптимизирует вызовы методов, поэтому производительность, вероятно, не является проблемой. Какие-нибудь мысли? (кроме правильного соглашения о регистре для имени поля)

РЕДАКТИРОВАТЬ: Спасибо за все ответы. Мне кажется, что, возможно, не все понимают мой вопрос. Когда публичное поле будет лучшим выбором, чем недвижимость? Почему это лучший выбор? Если единственной причиной является удобство (меньше ввода и беспорядка), то что может быть недостатком в том, чтобы компилятор генерировал свойство «под капотом» всякий раз, когда встречается открытое поле. По сути, было бы невозможно создать настоящее общедоступное поле (потому что все они были бы свойствами). Что было бы не так с этим? Спасибо.

Ответы [ 10 ]

12 голосов
/ 09 августа 2011

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

Имейте в виду, принцип открытия / закрытия .

5 голосов
/ 09 августа 2011

Вот краткое изложение плюсов и минусов публичных полей:

Преимущества

  • Меньше беспорядка в коде
  • Лучшая производительность (в некоторых случаях)

Недостатки

  • Представление не может быть изменено без изменения API
  • Инварианты не могут быть применены (, если поле не является неизменным)
  • Никаких дополнительных действий при доступе к этим полям не предпринимается

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

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

Подводя итог, приведу одну из моих любимых книг «Эффективная Ява» Дж. Блоха, пункт 14:

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

5 голосов
/ 09 августа 2011

Когда имеет смысл публично выставлять поле?

Среди других мест, на частных занятиях, как показано ниже.

public class MyOuterClass
{
      private class MyInnerClass
      {
            public int val ; // why bother w/boiler plate
      }
}
3 голосов
/ 09 августа 2011

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

Например, см .:

public const double PI

, определенный в System.Math.

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

Другой, о котором я могу подумать, это когда вам нужны классы в качестве контейнеров для простых операций (или просто для передачи большого количества параметров в метод), в качестве примера смотрите System.Windows.Point.Однако в большинстве случаев эти контейнеры моделируются как структуры.

3 голосов
/ 09 августа 2011

Я думаю, что это имеет смысл, когда вы хотите сгруппировать некоторые переменные / объекты (вроде как C struct). Например:

class Pixel {
  public int x;
  public int y;
  Color c;
  // Other Pixel related information
}

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

2 голосов
/ 12 августа 2011

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

/** 
 * A two-dimensional mathematical vector. Immutable so instances may be freely shared
 * without violating encapsulation.
 */
public class Vec2 {
    public final int x, y;

    // bunch of constructors and methods omitted
}

Обоснование: Маловероятно, что внутреннее представление нужно будет изменить или выполнить какую-либо операцию при чтении x или y.То есть использование сеттера здесь не приносит никакой пользы.

Однако это повлечет за собой некоторые затраты:

  1. Открытое окончательное поле позволит совершенно ясно, что класс является неизменным, с геттером вы должны доверять комментарию документации.(Обратите внимание, что отсутствие установщика не подразумевает неизменность, потому что какой-то другой метод мог бы назначить поле)все еще должен быть пропущен при чтении кода (по крайней мере, в Java, C # здесь лучше).
  2. Такое частое использование класса чрезвычайно низкого уровня возможно, и могут возникнуть проблемы при вызове.Да, виртуальная машина может выполнять встраивание во многих случаях, но, по крайней мере, для не финальных методов некоторые издержки могут остаться, даже если подклассы в настоящее время не загружены.
2 голосов
/ 09 августа 2011

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

JITter не превращает свойства в поля, он может встроить их, хотя я не буду обещать, что это происходит во всех случаях.

1 голос
/ 10 августа 2011

Лучшая практика в Java и C # уже давно заключается в использовании геттеров / установщиков или свойств для доступа к полям.

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

В крайних случаях вообще не должно быть никаких мутаторов.Последний этап создания класса неизменяемого заключается в том, чтобы никогда не делать изменяемые значения полей (помните, Java final не похож на C ++ const) напрямую доступными.И классы малого значения должны быть неизменными.Только метод получателя может обеспечить безопасный доступ к потенциально изменяемым полям путем создания копии (в C ++ у вас просто есть получатель, который возвращает значение).Вы могли бы отказаться от метода получения для тех полей, которые не требуют защитного копирования, но тогда для некоторых полей в классе может потребоваться метод получения, а для некоторых нет.Но это было бы странно,

1 голос
/ 09 августа 2011

Один сценарий, по крайней мере, в .NET, это взаимодействие с C API. Вы будете часто объявлять версии API-интерфейсов Windows на C # или VB, и для них часто используются открытые поля, потому что обычная причина сделать поля закрытыми - чтобы кто-то не связывался с ними за вашей спиной - не работает. В этом случае вы знаете , что что-то будет менять поля за вашей спиной - вот и вся цель иметь структуру!

Конечно, вы, как правило, не будете раскрывать эти некапсулированные структуры в коде приложения - вы будете рассматривать их как частные элементы модуля P / Invoke, поэтому код приложения по-прежнему не будет иметь дело с открытыми полями.

0 голосов
/ 09 августа 2011

Вы можете использовать в java открытое поле, а затем добавить к нему некоторую логику, например, если был получатель, использующий AspectJ, в том числе избегать записи в него, если не из определенного psckage и т. Д ...

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

Возвращаясь к вашему вопросу, поскольку в jit нет значительных улучшений в использовании открытых полей по сравнению с геттерами / сеттерами, и, поскольку в средах разработки есть автоматическое генерирование геттеров и сеттеров, в использовании геттеров и сеттеров нет никаких трудностей программиста.За годы Java-программирования я использовал открытые поля только пару раз и всегда заканчивал тем, что преобразовывал их в пары геттер / сеттер.

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