2016-12-06 2 views
2

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

public class MyClass { 
    private Integer myField; 

    public void setMyField(Integer myField) { 
     this.myField = myField; 
    } 

    public Integer getMyField() { 
     return myField; 
    } 

} 

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

Реализация 1

public boolean isAllowed() { 
    MyEnum.ALLOWED.getInt().equals(getMyField()); 
} 

Реализация 2

public boolean isAllowed() { 
    MyEnum.ALLOWED.getInt().equals(myField); 
} 

Edit: Это сообщение не имеет ответа в связанном вопросе (см комментарии к исходному сообщению)

+0

Если вы идете по инкапсуляции и абстракции Java, я думаю, что сначала предпочтительнее. Поскольку вы не открываете поля непосредственно. – SachinSarawgi

+0

Разница в смысле не имеет значения. Это скорее вопрос. Я бы выбрал ** реализацию 1 **, так как вы обязательно получите значение, которое хотите проверить, если у вас есть, например, какой-либо транскодификационный код – DamCx

+2

. Вы должны внимательно прочитать: http: // stackoverflow .com/questions/1568091/why-use-getters-and-setters – rafid059

ответ

5

Какие из следующих лучше? Является ли это даже основанным на мнениях или есть Есть ли какие-либо существенные различия? Может ли один или другой быть избранным в некоторых сценариях?

Это вопрос хорошей практики, я думаю. Разница в читаемости кода.

Как правило, вам следует избегать косвенности, если это не требуется. В текущем экземпляре MyClass есть информация в одном из этих полей для реализации операции. Ему не нужно скрывать свое внутреннее состояние к самому себе.
Таким образом, внутренний номер MyClass не имеет повода для обоснования использования getMyField() при прямом использовании поля myField.
Аксессуар getMyField() более подходит для использования клиентами класса.
Так что я думаю, что лучше в любом случае в вашем примере кода:

public boolean isAllowed() { 
    MyEnum.ALLOWED.getInt().equals(myField); 
} 

Edit:
Beyond читаемости, вот пример, почему у вас нет интереса к паре внутреннего состояния к публичный геттер.
Предположим, что на этапе разработки вы удаляете из класса метод public getMyField(), потому что он не нужен или не нужен больше для клиентов этого класса, если isAllowed() полагается на getMyField() в своей реализации, он будет сломан, и вы должны заменить его на myField.

+0

Этот ответ немного вводит в заблуждение, потому что пример чрезмерно упрощен и не имеет смыслового смысла. Имя getMyField не передает никакого намерения или смысла. Из метода были названы «getSecurityLevel», это лучше передало бы его намерение. На самом деле вы никогда не удалите этот метод, так как это изменит семантику программы. Вместо этого вы изменили бы реализацию getter, чтобы изменить поведение isAllowed. Главным для рассмотрения здесь является OCP. – Cliff

+0

@Cliff Почему вы хотите сделать вопрос более сложным, как есть? Вопрос в том, должен ли я использовать публичный геттер или личное поле из метода того же класса? Я не был конкретным, но мой пример, где я упоминаю об удалении метода геттера, относится к удалению на этапе разработки. Иногда вы предоставляете getters автоматически для многих полей (это помогает IDE) вашего класса, потому что вам нужно или вы думаете, что им нужно в то время, когда вы их создаете, и когда вы просматриваете класс в конце своей разработки, вы замечаете что геттер не должен предоставляться. – davidxxx

+0

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

-1

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

Странные функции или объекты могут никогда не видеть или даже изменять переменные-члены, за исключением того, что вы явно говорите им об этом с помощью setter и getters.

+1

Люди могут получить доступ к переменной «случайно» с помощью геттеров и сеттеров. Так в чем ваш смысл? – rafid059

+0

Легче получить доступ к «myField» случайно вместо «getMyField()». – Kapa11

1

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

+1

Не добавляет ли логика методам getter-setter, которые считаются плохой практикой? –

+1

Getters не должны иметь никакой логики. – Chris311

+1

@AlexErohin и Chris311 - конечно, логика разрешена в геттерах. В противном случае весь смысл «скрытия изменений в реализации» будет утрачен. Предположим, что поле теперь 'int'. И вы решили изменить реализацию на перечисление. Контракт для геттера остается неизменным, поскольку он публикуется и используется другими классами. Поэтому вместо того, чтобы иметь «return x;» в нем, у вас есть что-то вроде «return x.getIntValue()» - это логика в getter, и все отлично. – RealSkeptic

-1

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

https://www.tutorialspoint.com/java/java_encapsulation.htm

+1

Мои поля инкапсулированы. В статье не говорится о доступе к переменным внутри одного класса. – Chris311

0

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

public class MyClass { 
    private Integer myField; 

    MyClass(Integer myField){ 
     this.myField = myField; 
    } 

    //Only this method is offered nobody need to know you use myField to say true/false 
    public boolean isAllowed() { 
     MyEnum.ALLOWED.equals(myField); 
    } 

} 
+0

Предположим, что геттер и сеттер вызываются извне класса. – Chris311

+0

, то я бы добавил геттеры/сеттеры и сохранил один и тот же доступ к полю – cralfaro

+0

Итак, это идет с принятым ответом. – Chris311

3

Мой ответ не будет наиболее информативным, однако он будет получен из непосредственного опыта работы с этим шаблоном. При проектировании объекта часто возникает соблазн напрямую обращаться к полям-членам, а не полагаться на аксессуры. Желание проистекает из желания упростить объект и избежать добавления беспорядка из методов, которые просто возвращают значение. Берем пример еще один шаг, чтобы добавить Context & значение:

public class MyClassmate { 
    private Integer age; 

    public MyClassmate(Integer age) { 
     this.age = age; 
    } 

    public void setAge(Integer age) { 
     this.age = age; 
    } 

    public Integer getAge() { 
     return age; 
    } 

} 

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

public Integer calculateScore() { 
    if(age > 21) return 100 - getNumberOfIncorrectAnswers(); 
    //Add 10% before for younger students 
    else return (100 - getNumberOfIncorrectAnswers()) + 10; 
} 

Ваш объект может затем расти новые функции с помощью методов, опирающихся на поле возраста, где вы будете продолжать использовать его непосредственно. Позже вы можете изменить способ создания возраста и вывести его из сети. Возможно, вы не захотите включить сетевую логику в конструктор, потому что это дорогостоящая операция, которая должна запускаться только по мере необходимости. Метод calculateScore() мог бы установить сетевое соединение и узнать возраст, но тогда все остальные методы полагались бы на возраст. Но что, если calculateScore выглядел следующим образом ?:

public Integer calculateScore() { 
    if(getAge() > 21) return 100 - getNumberOfIncorrectAnswers(); 
    //Add 10% before for younger students 
    else return (100 - getNumberOfIncorrectAnswers()) + 10; 
} 

Затем можно повысить объект меняющийся, как он производный возраст, не касаясь метода calculateScore(). Это означает, что ваш метод следует принципу Open Closed (OCP). Он открыт для улучшения, но закрыт для изменения, или вам не нужно было менять источник метода, чтобы изменить его возраст.

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

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

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

+0

Интересный встречный пример. Возраст, возможно, слишком простое свойство для примера, но, тем не менее, хороший пример. – davidxxx

+0

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

+0

@Cliff: В вашем примере вы используете геттер. Если возраст будет извлечен из сети, нужно скорее использовать ассемблер или фабрику для создания «MyClassmate». Я не думаю, что логика должна идти прямо в «MyClassmate». Иначе это уже не геттер, а метод 'computeAge()'. – Chris311

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