Вы действительно используете шаблон шаблона. Есть две основных вещей, которые вы могли бы сделать, чтобы «скрыть» деталь от внешних пользователей:
1) Понимание ваших access modifiers:
Access Levels
Modifier | Class | Package | Subclass | World |
--------------------------------------------------
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
no modifier | Y | Y | N | N |
private | Y | N | N | N |
Замыкания детерминированных хакеров издевательств своего пути в прошлом этих защит с отражением, это может держите случайных кодеров от случайно вызывающих методов, которые лучше всего держать вне их пути. Кодеры оценят это. Никто не хочет использовать загроможденный API. В настоящее время b.doWork()
является protected
. Так что это будет видно только в вашем main()
, если ваш main()
находится в классе A
(это не так), подкласс B
(это не так) или в том же пакете (непонятно, что вы не опубликовали никаких сведений о пакете (пакетах) ваш код находится в).
Это вопрос, который вы пытаетесь защитить от наблюдения b.doWork()
? Если создаваемый вами пакет - это то, что вы разрабатываете, это может быть не так уж плохо. Если многие люди топают в этом пакете, возившись со многими другими классами, вряд ли они будут близко знакомы с классами A
и B
. Это тот случай, когда вы не хотите, чтобы все висели там, где каждый может это увидеть. Здесь было бы неплохо разрешить доступ только класса и подкласса. Но не существует модификатора, который позволяет доступ к подклассам без разрешения доступа к пакету. Пока вы подклассифицируете protected
- это лучшее, что вы можете сделать. Имея это в виду, не создавайте пакеты с огромным количеством классов. Держите упаковки плотными и целенаправленными. Таким образом, большинство людей будет работать вне пакета, где все выглядит красиво и просто.
В двух словах, если вы хотите, чтобы main()
не позвонил b.doWork()
положил main()
в другой упаковке.
package some.other.package
public final class Main {
...
}
2) Значение этого следующего куска совета будет трудно понять, с текущим кодом, потому что речь идет о решении вопросов, которые будут только придумывают, если ваш код расширяются дальше. Но это на самом деле тесно связана с идеей защиты людей от видящих вещей, как b.doWork()
What does "program to interfaces, not implementations" mean?
В коде это означает, что было бы лучше, если бы главный выглядел так:
public static void main(String[] args) {
A someALikeThingy = new B(); // <-- note use of type A
someALikeThingy.work(); //The name is silly but shows we've forgotten about B
//and know it isn't really just an A :)
}
Зачем? Что использует тип A
против типа B
вопрос? Ну A
ближе к интерфейс. Заметьте, здесь я не просто имею в виду то, что вы получаете, когда используете ключевое слово interface
.Я имею в виду, что тип B
представляет собой конкретную реализацию типа A
, и если мне не обязательно писать код против B
, то я бы предпочел не потому, что кто знает, что странно, но не A
вещей B
имеет. Это трудно понять здесь, потому что код в основном короткий & сладкий. Кроме того, общественность интерфейсов от A
и B
не так уж и отличается. Они оба имеют только один общедоступный метод work()
. Представьте себе, что main()
был длинным и запутанным. Представьте себе, что B
имел всевозможные методы, не зависящие от него. Теперь представьте, что вам нужно создать класс C
, с которым вы хотите справиться. Разве не было бы приятно видеть, что в то время как главная была подана B
, что, насколько каждая строка в главном знает, что B
- это просто простая вещь A
. За исключением части после new
, это может быть правдой и избавит вас от необходимости делать что-либо до main()
, но обновление этого new
. Действительно, разве это не значит, что использование строго типизированного языка иногда может быть приятным?
< декламация >
Если вы думаете, даже обновить эту часть после new
с B()
слишком много работы, вы не одиноки. Эта особая навязчивая идея - вот что дало нам dependency injection movement, который породил кучу фреймворков, которые были в большей степени связаны с автоматизацией построения объектов, чем простая инъекция, которую может позволить любой конструктор.
</декламация >
Update:
Я вижу из ваших комментариев, что вы неохотно создавать небольшие плотные пакеты. В этом случае рассмотрите отказ от шаблона шаблона, основанного на наследовании, в пользу шаблона стратегии на основе композиции. Вы все еще получаете полиморфизм. Это просто не происходит бесплатно. Еще немного написания кода и косвенности. Но вы можете изменить состояние даже во время работы.
Это будет казаться противостоящим интуитивно понятным, потому что теперь doWork()
должно быть общедоступным. Что это за защита? Ну теперь вы можете скрыть B
полностью за или даже внутри AHandler
. Это какой-то дружелюбный к человеку класс фасадов, который содержит то, что раньше было вашим шаблоном, но выставляет только work()
. A
может быть просто interface
, так что AHandler
до сих пор не знает, что он имеет B
. Этот подход популярен среди толпы инъекций зависимостей, но, конечно же, не имеет универсальной привлекательности. Некоторые делают это слепо каждый раз, что раздражает многих. Вы можете узнать больше об этом здесь: Prefer composition over inheritance?
"один легко сможет случайно называют b.doWork()". В самом деле? Он защищен, поэтому его могут вызвать только экземпляры A или B. –
К сожалению, поскольку он защищен, все классы из пакета могут его вызвать. Разделение пакетов - это путь, хотя я бы предпочел избегать использования пакетов с 1 или 2 классами. –
Нет !! Вы описываете модификатор доступа по умолчанию (т. Е. Нет). Защищенные средства «только меня или классы, которые расширяют меня, могут использовать это» –