Наиболее краткое описание того, когда использовать вложенный класс: , когда этот класс логически является частью API внешнего класса или когда он инкапсулирует поведение, характерное для внешнего класса .
Например, Map.Entry
: это запись в отображении. Это логически часть API Map
, поэтому имеет смысл поместить его в Map
.
Другим распространенным примером является Классы строителей : вы используете Builder
для создания вещи, поэтому имеет смысл поместить ее внутрь этой вещи.
Это классы, которые вы действительно используете только в контексте использования внешних классов: иногда вы можете использовать Map.Entry
сам по себе как некоторый класс пары; а иногда вы можете захотеть использовать Builder
сам по себе, например, в качестве параметра метода, который помещает вещи в этот компоновщик, но на самом деле не выполняет саму конструкцию. Эти случаи, вероятно, редко бывают далеки от кода, который также использует внешний класс: вы все еще используете некоторый аспект API внешнего класса, поэтому они по-прежнему логически принадлежат этому API.
Вы можете поместить такие классы на верхний уровень, рядом с "основным" классом. Есть несколько причин, по которым вы можете этого не делать:
- Это загромождает пространство имен. Если у вас есть классы
Foo
, Bar
, Baz
и т. Д., Наличие FooBuilder
, BarBuilder
, BazBuilder
на верхнем уровне просто затрудняет просмотр "полезных" классов верхнего уровня.
- Буферы протокола Google генерируют класс
Builder
для каждого типа сообщений. Учитывая количество буферов протокола, используемых в коде Google, этот беспорядок был бы слишком громоздким.
- Вложенные классы имеют доступ к закрытым полям внешнего класса, что может помочь вам делать определенные вещи без ненужного раскрытия этих полей.
- Вы можете ссылаться на вложенные классы, указав внешнее имя, например,
Outer.Builder
, вместо того, чтобы явно import some.pkg.OuterBuilder
, а также import some.pkg.Outer
. По общему признанию, я действительно не забочусь о количестве импорта, так как я просто держу их свернутыми в intellij.
Вы также можете использовать их для инкапсуляции внутренней логики или промежуточного состояния в классе: например, мне нравится определять частные вложенные классы, когда я нахожу себя передающим те же N параметров между частными методами в классе. Это то, что вы не хотите, чтобы люди вне вашего класса заботились; это просто удобно внутри класса.