Skip to content

Latest commit

 

History

History
127 lines (98 loc) · 6.48 KB

classes_for_static.md

File metadata and controls

127 lines (98 loc) · 6.48 KB

Введение

Если у нас возникает необходимость написать класс, содержащий только статические методы и переменные, то: подумайте - нужен ли вам такой класс?

Если вы понимаете, что вы не пишите в процедурном стиле на Java, то давайте ответим на вопрос: зачем такой класс может быть нужен?

С помощью таких классов удобно собирать вместе общие методы работы с данными, например, как сделано в java.lang.Math, для методов статической генерации объектов, как в java.util.Collections, т.е в основном - для создания классов с утилитами.

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

Советы

Главное, что необходимо учесть:

  • Невозможность создания объекта класса.
  • Исключить возможность наследования.

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

Как запретить использование конструктора пользователем?

  • Сделать класс абстрактным - использовать abstract.
  • Объявить конструктор private.

Рассмотрим, какой из способов подойдет нам в нашем случае:

Использование abstract

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

Приватный конструктор

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

Допустим, AssertionError.

Исключение наследования

Дабы избежать случайного наследования таких классов, как наш - необходимо объявить такой класс final. Т.е сказать, что такой класс является финальным, полностью законченным и не предназанченным для наследования.

Все вместе:

Пример такого класса:

/**
 * Illustrate how we can create class for only static methods and fields.
 * Good way.
 */
public final class ClassForStatic {

    public static String st_string = "Hello";

    public static void method() {
        System.out.println("Static method");
    }

    /**
     * If we create instance of class - we throw Error.
     */
    private ClassForStatic() {
        throw new AssertionError();
    }

    /**
     * We have error in this method! - cause we have only private constructor,
     * and if we create instance of our class - we throw error.
     */
    public static ClassForStatic errorThrow() {
        return new ClassForStatic();
    }
}

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

Классы для констант

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

Вынеся в такие классы данные вы разграничите логику, что всегда хорошо. Т.е например у вас есть константы для User, Country и т.д, можно все запихнуть в один класс и смешать все в кучу, а можно сделать вот так:

public class Constants {
    public static final class Category {
        private Category() {
            throw new AssertionError();
        }

        public static final int NAME_LENGTH = 100;
    }

    public static final class Country {
        private Country() {
            throw new AssertionError();
        }

        public static final int NAME_LENGTH = 100;
    }

    public static final class Series {
        private Series() {
            throw new AssertionError();
        }

        public static final int COMMENT_LENGTH = 255;
    }

    public static final class User {
        private User() {
            throw new AssertionError();
        }

        public static final int LOGIN_LENGTH = 25;
        public static final int NAME_LENGTH = 100;
    }
}

Теперь вы можете обращаться к константе как:

Constants.User.NAME_LENGTH

И это намного понятнее, чем если бы все было в одном классе.