Альтернативы статическим методам в Java

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

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

13
задан Durandal 22 February 2014 в 21:47
поделиться

9 ответов

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

Запуск с Вашего комментария "Я должен создать экземпляр его только для получения строки, которая действительно статична в поведении",

Это не абсолютно корректно. Если Вы хорошо выглядите, Вы не изменяете поведение своего базового класса, просто изменив параметр для метода. Другими словами, Вы изменяете данные, не алгоритм.

Наследование более полезно, когда новый подкласс хочет изменить способ, которым работает метод, если бы просто необходимо изменить "данные" использование класса для работы, вероятно, подход как это добился бы цели.

class ModelBase {
    // Initialize the queries
    private static Map<String,String> selectMap = new HashMap<String,String>(); static {
        selectMap.put( "Album", "select field_1, field_2 from album");
        selectMap.put( "Artist", "select field_1, field_2 from artist");
        selectMap.put( "Track", "select field_1, field_2 from track");
    }

    // Finds all the objects for the specified class...
    // Note: it is better to use "List" rather than "ArrayList" I'll explain this later.
    public static List findAll(Class classToFind ) {
        String sql = getSelectSQL( classToFind );
        results = execute( sql );
        //etc...
        return ....
    }

    // Return the correct select sql..
    private static String getSelectSQL( Class classToFind ){
        String statement = tableMap.get( classToFind.getSimpleName() );
        if( statement == null ) {
            throw new IllegalArgumentException("Class " + 
                 classToFind.getSimpleName + " is not mapped");
        }
        return statement;

    }
}

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

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

// Client usage:

...
List albums = ModelBase.findAll( Album.class );

...

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

// Second option, instance used under the hood.
class ModelBase {
    // Initialize the queries
    private static Map<String,ModelBase> daoMap = new HashMap<String,ModelBase>(); static {
        selectMap.put( "Album", new AlbumModel() );
        selectMap.put( "Artist", new ArtistModel());
        selectMap.put( "Track", new TrackModel());
    }

    // Finds all the objects for the specified class...
    // Note: it is better to use "List" rather than "ArrayList" I'll explain this later.
    public static List findAll(Class classToFind ) {
        String sql = getSelectSQL( classToFind );
        results = execute( sql );
        //etc...
        return ....
    }

    // Return the correct select sql..
    private static String getSelectSQL( Class classToFind ){
        ModelBase dao = tableMap.get( classToFind.getSimpleName() );
        if( statement == null ) {
            throw new IllegalArgumentException("Class " + 
                 classToFind.getSimpleName + " is not mapped");
        }
        return dao.selectSql();
    }
    // Instance class to be overrided... 
    // this is "protected" ... 
    protected abstract String selectSql();
}
class AlbumModel  extends ModelBase {
    public String selectSql(){
        return "select ... from album";
    }
}
class ArtistModel  extends ModelBase {
    public String selectSql(){
        return "select ... from artist";
    }
}
class TrackModel  extends ModelBase {
    public String selectSql(){
        return "select ... from track";
    }
}

, И Вы не должны изменять клиентский код и все еще иметь власть полиморфизма.

// Client usage:

...
List albums = ModelBase.findAll( Album.class ); // Does not know , behind the scenes you use instances.

...

я надеюсь, что это помогает.

примечание финала А по использованию Списка по сравнению с ArrayList. Это всегда лучше к программе к интерфейсу, чем к реализации, этот способ, которым Вы делаете свой код более гибким. Можно использовать другую Реализацию списка, которая быстрее, или делает что-то еще, не изменяя клиентский код.

2
ответ дан 2 December 2019 в 01:49
поделиться

Статичный неправильная вещь использовать здесь.

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

Каждая таблица имеет различный класс, и это в порядке. Так как у Вас может только когда-либо быть одна из каждой таблицы, ограничить количество экземпляров каждого класса к одному (используйте флаг - не делают это Singleton). Заставьте программу создать экземпляр класса, прежде чем это получит доступ к таблице.

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

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

4
ответ дан 2 December 2019 в 01:49
поделиться

Почему не использование аннотаций? Они fitpretty хорошо, что Вы делаете: добавить метаинформацию (здесь SQL-запрос) к классу.

1
ответ дан 2 December 2019 в 01:49
поделиться

Как предложено, Вы могли использовать аннотации, или Вы могли переместить статические методы для объектов фабрики:

public abstract class BaseFactory<E> {
    public abstract String getSelectSQL();
    public List<E> findAll(Class<E> clazz) {
       // Use getSelectSQL();
    }
}

public class AlbumFactory extends BaseFactory<Album> {
    public String getSelectSQL() { return "select * from albums....."; }
}

, Но это не очень хороший запах, чтобы иметь объекты без любого состояния.

1
ответ дан 2 December 2019 в 01:49
поделиться

Если Вы передаете Класс findAll, почему Вы не можете передать класс getSelectSQL в ModelBase?

0
ответ дан 2 December 2019 в 01:49
поделиться

астерит: Вы подразумеваете, что getSelectSQL существует только в ModelBase, и он использует переданный в классе для создания имени таблицы или чего-то как этот? Я не могу сделать этого, потому что некоторые Модели имеют wildy differeing избранные конструкции, таким образом, я не могу использовать универсальный "выбор * от" + classToTableName ();. и любая попытка получить информацию из Моделей об их избранной конструкции сталкивается с той же проблемой от исходного вопроса - Вам нужен экземпляр Модели или некоторого необычного отражения.

штуковина: Я буду definatly взглянуть в аннотации. Хотя я не могу не задаться вопросом, что люди сделали с этими проблемами, прежде чем было отражение?

0
ответ дан 2 December 2019 в 01:49
поделиться

У Вас могли быть свои методы SQL как методы экземпляра в отдельном классе.
Тогда передают объект модели в конструктора этого нового класса и называют его методы для получения SQL.

0
ответ дан 2 December 2019 в 01:49
поделиться

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

Короткий ответ (Java или.NET): Вы не можете. Более длинный ответ - Вы можете, если Вы не возражаете для использования аннотации уровня Класса (отражение) или инстанцирование объекта (метод экземпляра), но ни один не является действительно 'чистым'.

Посмотрите мой предыдущий (связанный) вопрос здесь: , Как обработать статические поля, которые варьируются классом с реализацией , я думал, ответы были все действительно Ламе и упустили суть. Ваш вопрос намного лучше сформулирован.

0
ответ дан 2 December 2019 в 01:49
поделиться

Я соглашаюсь со Штуковиной: Вы или смотрите на аннотации или своего рода конфигурационный файл. Я смотрел бы на, в спящем режиме и другие платформы ORM (и возможно даже библиотеки как log4j!), чтобы видеть, как они обрабатывают загрузку метаинформации уровня класса.

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

-1
ответ дан 2 December 2019 в 01:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: