Аноним против названных внутренних классов? - лучшие практики? - PullRequest
43 голосов
/ 03 апреля 2009

У меня есть класс, назовем его LineGraph, который отображает линейный график. Мне нужно создать его подкласс, но производный класс используется только в одном месте и связан с классом, который его использует. Поэтому я использую внутренний класс.

Я вижу два способа сделать это:

Анонимный внутренний класс

public class Gui {
    LineGraph graph = new LineGraph() {
        // extra functionality here.
    };
}

Именованный внутренний класс

public class Gui {
    MyLineGraph graph = new MyLineGraph();

    private class MyLineGraph extends LineGraph {
        // extra functionality here.
    }
}

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

Ответы [ 15 ]

49 голосов
/ 03 апреля 2009

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

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

Они очень похожи, так что ни один из них не меняет правила игры. Я просто думаю, что для ясности будет полезно, если вы используете анонимные внутренние классы для одноразовых и называете внутренние классы, когда они используются в классе несколько раз.

36 голосов
/ 03 апреля 2009

(контрапункт Даниэлю Лью)

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

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

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

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

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

Мое личное предпочтение - использовать неанонимные классы, поскольку они обеспечивают большую гибкость при изменении кода позже.

10 голосов
/ 03 апреля 2009

Зачем вам это нужно подкласс? Если это просто переопределить существующий виртуальный метод, я думаю, что анонимный внутренний класс в порядке. Если вы добавляете дополнительную функциональность, я бы использовал именованный класс. Хотя я бы сделал это вложенным классом (т.е. с модификатором static) - я считаю, что его легче рассуждать:)

8 голосов
/ 03 апреля 2009

Сделайте самое простое, что могло бы сработать : используйте анонимный внутренний класс.

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

(Вы сделали бы то же самое с переменными - поместив их в наиболее конкретную область. Имеет смысл сделать то же самое с другими исходными ресурсами.)

4 голосов
/ 03 апреля 2009

Анонимные внутренние классы трудно отлаживать в Eclipse (вот что я использую). Вы не сможете просматривать значения переменных / вводить значения, просто щелкнув правой кнопкой мыши.

3 голосов
/ 30 июля 2009

Мое эмпирическое правило: если анонимный внутренний класс будет маленьким, придерживайтесь анонимного класса. Малый, определяемый как около 20-30 строк или меньше. Если он будет длиннее, он станет нечитаемым, на мой взгляд, поэтому я делаю его именованным внутренним классом. Я помню, как однажды увидел более 4000 строк анонимного внутреннего класса.

3 голосов
/ 03 апреля 2009

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

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

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

2 голосов
/ 20 ноября 2010

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

2 голосов
/ 03 апреля 2009

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

1 голос
/ 27 мая 2012

Анонимные классы:

  • не может иметь ничего static в определении (статический класс, статическое поле, статический инициализатор и т. Д.)
  • поля не могут быть проверены в Eclipse
  • нельзя использовать как тип (Foo$1 myFoo=new Foo$1(){int x=0;} не работает)
  • невозможно найти по имени класса в Eclipse (поиск Foo$1 не работает для меня)
  • не может быть повторно использован

Однако анонимные классы могут иметь инициализатор, такой как {super.foo(finalVariable+this.bar);}

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

Я лично предпочитаю анонимные внутренние классы, если ограничения не применяются, потому что:

  • Я знаю, что любые дополнительные поля упоминаются только в определении класса.
  • Eclipse может легко конвертировать их во вложенные классы.
  • Мне не нужно копировать переменные, которые я хочу использовать. Я могу просто объявить их окончательными и ссылаться на них. Это особенно полезно, когда у меня много параметров.
  • Код, который взаимодействует, близок друг к другу.
...