ищем конкретный вариант использования, когда подклассу и классу в одном и том же пакете необходим доступ к защищенному полю или методу ...
Ну, для меня такой вариант использования является скорее общим, чем конкретным, и он вытекает из моих предпочтений:
- Начните с как можно более строгого модификатора доступа, прибегая к более слабому (-ым) модификатору (-ам) позже, если это будет сочтено необходимым.
- Имейте модульные тесты в том же пакете, что и проверенный код.
Сверху я могу начать проектирование для своих объектов с модификаторами доступа по умолчанию (я бы начал с этого, private
но это усложнило бы модульное тестирование):
public class Example {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
void doSomething() {} // default access
}
static class Unit2 {
void doSomething() {} // default access
}
static class UnitTest {
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Примечание стороны в приведенном фрагменте, Unit1
, Unit2
и UnitTest
являются вложенными в Example
для простоты изложения, но в реальном проекте, я, скорее всего , эти классы в отдельных файлах (и UnitTest
даже в отдельном каталоге ).
Затем, когда возникнет необходимость, я бы ослабил контроль доступа по умолчанию protected
:
public class ExampleEvolved {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
protected void doSomething() {} // made protected
}
static class Unit2 {
protected void doSomething() {} // made protected
}
static class UnitTest {
// ---> no changes needed although UnitTest doesn't subclass
// ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Видите ли, я могу сохранить код модульного теста ExampleEvolved
без изменений, поскольку защищенные методы доступны из одного пакета, даже если доступ к объекту не является подклассом .
Требуется меньше изменений => более безопасная модификация; В конце концов я изменил только модификаторы доступа и не изменил, какие методы Unit1.doSomething()
и что Unit2.doSomething()
делают, поэтому вполне естественно ожидать, что код модульного теста продолжит выполняться без изменений.
protected
только подкласс? Честно говоря, долгое время у меня было впечатление, что это поведениеprotected
- только класс и подкласс, а такжеinternal
библиотека / пакет. Он также имеетprotected internal
что эквивалентно Javaprotected
.ИМХО, это было плохое дизайнерское решение в Java.
Просто размышления, но я думаю, что они хотели, чтобы уровни доступа были в строгой прогрессии: private - «package» - protected - public. Они не хотели иметь иерархию, где некоторые поля были бы доступны для пакета, но не для подклассов, некоторые доступны для подклассов, но не для пакета, а некоторые - оба.
Тем не менее, по моему скромному мнению, они должны были пойти другим путем: сказали, что защищенный виден только классу и подклассам, а этот пакет виден классу, подклассам и пакету.
У меня часто есть данные в классе, которые должны быть доступны для подклассов, но не для остальной части пакета. Мне трудно придумать случай, когда обратное было правдой. У меня было несколько редких случаев, когда у меня был набор взаимосвязанных классов, которые должны обмениваться данными, но которые должны обеспечивать безопасность этих данных извне. Хорошо, поместите их в пакет и т. Д. Но у меня никогда не было случая, когда я хочу, чтобы пакет делился данными, но я хочу сохранить его от подклассов. Хорошо, я могу представить себе ситуацию. Я полагаю, если этот пакет является частью библиотеки, которая может быть расширена классами, о которых я ничего не знаю, по тем же причинам, по которым я бы сделал данные в классе частными. Но более распространенным является желание сделать данные доступными только для класса и его детей.
Есть много вещей, которые я храню в тайне между мной и моими детьми, и мы не делимся ими с соседями. Очень мало, что я держу в секрете между мной и соседями и не делюсь с моими детьми. :-)
источник
Хороший пример, который сразу приходит на ум, - это служебные классы, которые часто используются в пакете, но вам не нужен общедоступный доступ (скрытые классы загрузки изображений с диска, классы создания / уничтожения дескрипторов и т. Д.). .) вместо того, чтобы делать все [эквивалент Java
friend access modifier or idiom
вC++
] любого другого класса, все автоматически доступно.источник
Варианты использования для модификатора защищенного / пакетного доступа аналогичны вариантам для модификаторов дружественного доступа в C ++.
Один из вариантов использования - при реализации шаблона Memento .
Объект memento должен иметь доступ к внутреннему состоянию объекта, чтобы удерживать его, чтобы он служил в качестве контрольной точки для операций отмены.
Объявление класса в одном и том же пакете является одним из возможных способов достижения шаблона Memento, поскольку в Java нет модификатора доступа «друг» .
источник
симметрия?
Такой доступ редко требуется, поэтому доступ по умолчанию используется так редко. Но иногда фреймворки хотят его для сгенерированного кода, где классы-оболочки помещаются в один и тот же пакет, который напрямую взаимодействует с вашими классами, обращаясь к членам вместо аксессоров по соображениям производительности. Подумайте, GWT.
источник
Иерархия инкапсуляции Java хорошо определена:
Класс -> Пакет -> Наследование
«Защищенный» является более слабой формой конфиденциальности, чем пакет по умолчанию, как решают разработчики Java. Доступ к элементам пакета по умолчанию ограничен подмножеством объектов, которым разрешен доступ к защищенным элементам.
С математической точки зрения и с точки зрения реализации имеет смысл иметь ваши наборы сущностей, которым разрешен доступ к вещам, которые будут вложенными. (Вы не можете вложить свой набор доступа к пакетам в свой набор защищенного доступа, потому что классам разрешено наследовать от других пакетов).
С концептуальной точки зрения имеет смысл иметь что-то в java.util, чтобы быть «более дружелюбным» с другим классом в пакете, чем что-то в com.example.foo.bar, который подклассирует это. В первом случае классы могут быть написаны одним и тем же автором или, по крайней мере, программистами из одной организации.
источник