Это хорошая практика переопределения методов с более высокой видимостью?

отвечая на этот вопрос: как GUI-использование paintcomponent () для инициализации GUI, а затем для добавления GUI на основе мыши я заявил следующее:

вы не переопределить paintComponent() правильно. Это защищенный метод, не публичный. Если добавить @Override аннотация к этому методу тогда компилятор будет жаловаться.

но @peeskillet мудро указал на это:

компилятор не будет жаловаться public или protected С paintComponent. Вы можете переопределить с более высокой видимостью, но не a Нижний. public выше protected Так что нет никаких проблем.

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

дополнительное соглашение

ссылке JComponent.paintComponent() javadoc.

изображение Netbeans не жалуется вообще:

enter image description here

8 ответов


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

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

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


EDIT: меня попросили уточнить, почему это важно для инъекции зависимостей. Я могу говорить только на основе собственного опыта, сначала с Guice, а теперь с Dagger.

Dagger использует инъекцию конструктора, которая в основном означает, что класс получит все свои зависимости, предоставленные в качестве аргументов конструктору (и только там) и что код клея, связывающий это вместе, указан в модуле Dagger@. В этом модуле обычно очень удобно возвращать подкласс класса библиотеки, дополняя операторы log или предоставляя пользовательский метод toString (). Для того, чтобы на самом деле DO это без трюков отражения класс не может быть окончательным, и вам нужно иметь возможность переопределять методы и использовать поля в суперклассе напрямую. Следовательно, нет конечных классов, и оба типа должны быть в не менее protected вместо private!

(и я могу настоятельно рекомендуем использовать Dagger, потому что он перемещает разрешение зависимостей в компиляторе java, предоставляя IDE информацию, необходимую для решения проблем во время компиляции, а не в зависимости от магии во время выполнения в дикой природе. Я все еще поражен пониманием экосистемы Java, которое дизайнеры Dagger должны были даже get эта идея, а затем реализовать ее)


Из Учебника Java,управление доступом к членам класса:

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

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

этот совет направлен на уменьшить связь:

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

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


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


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


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

  • измените некоторые функции (переопределив метод)
  • расширить интерфейс класса (путем добавления нового открытого метода)

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

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

Btw: как указано здесь запрещение этой языковой функции может быть даже вредным.


переопределенные методы, как и все другие методы, должны быть объявлены public Если вы хотите, чтобы внешний код мог вызывать их (если у вас нет выбора, потому что переопределенный метод объявлен как public). В вашем случае переопределенный метод paintComponent должен вызываться только Swing, таким образом, сохраняя его protected это лучший вариант.


чтобы добавить к тому, что говорил Франсуа, принцип ООП в игре здесь "Открыть-Закрыть Принципа, " который говорит, что вы должны иметь возможность расширять, но не изменять объект. "Повышение" видимости метода путем его переопределения-это просто расширение, как указал Франсуа.


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

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