Нарушают ли константы stati c "инкапсуляцию"? - PullRequest
0 голосов
/ 20 июня 2020

Хорошо, поэтому я использую эту книгу: Ядро Java Том I - Основы.

Он определяет инкапсуляцию следующим образом:

Инкапсуляция (иногда называемая сокрытием информации) это ключевая концепция в работе с объектами. Формально инкапсуляция - это просто объединение данных и поведения в одном пакете и сокрытие деталей реализации от пользователей объекта.

Из поиска в SO я знаю, что инкапсуляция и скрытие информации - это разные концепции, но используется вместе. Но давайте придерживаться определения книги (в котором говорится, что инкапсуляция == скрытие реализации), поскольку в этом вопросе используются примеры из книги.

public class Math
{
 . . .
 public static final double PI = 3.14159265358979323846;
 . . .
}

В книге говорится, что это не нарушает инкапсуляцию как константа. Но разве приведенный выше код не нарушает реализацию , скрывающую часть инкапсуляции (по определению в книге), поскольку PI виден не только классу, но и остальной части программы.

На самом деле мой вопрос возможный дубликат этого: Нарушает ли переменная publi c stati c const идеологию инкапсуляции? (хотя и помечена C ++), но в ответе говорится, что она нарушает инкапсуляцию (противоречит книге) и все нормально. Я понимаю, если мой вопрос закрыт из-за возможного дублирования

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

public class System
{
 . . .
 public static final PrintStream out = . . .;
 . . .
}

Ответы [ 3 ]

3 голосов
/ 20 июня 2020

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

Первый пример, который вы привели, - это константа PI, а второй - это пример, который обеспечивает доступ к константе out в System; предположительно, чтобы использовать какой-то код, например System.out.println("HelloWorld!");. Как уже упоминалось другими, PI фактически является просто константой, и у пользователей константы нет средств, с помощью которых можно изменить или повлиять на значение. Пользователям PI по-прежнему необходимо ссылаться на константу (которая составляет здесь API) в своем коде. Если бы PI был изменен (маловероятно, но кто знает), пользователи были бы в безопасности от последствий этого изменения, потому что им все равно пришлось бы перекомпилировать код.

Полезный способ подумать об инкапсуляции - это подумайте, что потребуется для нарушения инкапсуляции. Эффективное Java 3-е издание хорошо описывает это в правиле 16, предполагая, что без надлежащей инкапсуляции «вы не можете изменить представление, не изменяя API, вы не можете принудительно применять инварианты, и вы не можете предпринять вспомогательные действия, когда поле доступ. "

Очень явным нарушением вышеизложенного будет следующий класс (также в пункте 16 действующего Java):

class Point {
  public double x;
  public double y;
}

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

Теперь давайте посмотрим на второй предоставленный вами пример:

public class System
{
 . . .
 public static final PrintStream out = . . .;
 . . .
}

Это похоже на пример PI выше, но есть ключевое отличие: рассматриваемое поле является PrintStream. Хотя само поле out является явной частью этого API, которую теперь может быть трудно изменить (теперь, когда оно открыто, клиенты будут использовать и полагаться на него), тип PrintStream - это класс, который на самом деле интересен здесь: пользователи будут ссылаться на методы класса. Здесь у нас есть ключевая функциональность в API PrintStream, которая может развиваться с течением времени без прерывания использования. Также возможно, что в будущем константа out будет изменена для обозначения другого подкласса PrintStream, и пользователи API не будут затронуты.

Надеюсь, что это поможет.

1 голос
/ 20 июня 2020

Stati c литералы не являются частью какого-либо объекта, это просто данные, присвоенные глобальной переменной для убеждения. Таким образом, это не нарушение инкапсуляции как таковой, а полное отсутствие объектной ориентации. Способ OOP состоит в том, чтобы вообще не иметь глобальной константы и определить объект, который решает вашу проблему. *

0 голосов
/ 20 июня 2020

Я не думаю, что stati c подпадает под принцип OOP. Таким образом, он не нарушает и не соблюдает.

...