Где должен жить главный

Это часть краткой серии статей о хороших привычках для программистов Java.

В программе на Java должен быть метод с сигнатурой

В статье «Как избавиться от Main и уменьшить статику» мы перенесли большую часть нашей логики из метода public void static main в класс Square и в итоге получили такой код:

public class Square {
    private float sideLength = 0.0f;

    public static void main(String args[]) {
        Square square = new Square();
        square.setSideLength(3.2f);
        System.out.println("The area of the square is " + square.getArea());
        System.out.println("The perimiter of the square is " + square.getPerimeter());
    }

    public void setSideLength(float length) {
        sideLength = length;
    }

    public float getArea() {
        return sideLength * sideLength;
    }

    public float getPerimeter() {
        return 4 * sideLength;
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Не лишним будет просмотреть этот пост. В нем я отметил, что мы должны думать о main как о договорной точке встречи со средой выполнения Java. Именно так среда выполнения Java находит место для запуска вашей программы, и это ее основная роль. Учитывая это, принадлежит ли main в Square? На самом деле квадрат не имеет ничего общего с формой. Если я попрошу вас назвать свойства квадрата, которые следует моделировать классом Square, вы расскажете мне о длине стороны, формулах для площади и периметра квадрата и тому подобном (может быть, о том, какие углы измеряются для квадрата, и т.д.), но вы не скажете, что у них есть контрактная точка входа, через которую среда выполнения Java может запустить Java-программу.

Поэтому, учитывая это, не следует думать, что main является методом Square. Может быть удобно поместить его туда: в этом случае он сохраняет всю вашу программу в одном файле. Но концептуально это странно.

Я продолжу. Что если вы расширите свою программу, чтобы жестко закодировать значения для других фигур (например, круг, треугольник) и вывести их площади и периметры? Будете ли вы настаивать на сохранении main в Square? Почему Square, а не Circle?

Вот похожий момент. Допустим, вы читатель расширенной программы, а не ее автор: узнали бы вы, в каком файле/классе находится волшебный метод main из таких имен классов, как Square, Circle, Triangle? Скажете ли вы себе: «О, это должно быть в Square. Зачем ему быть где-то еще?». Когда программы начинают становиться немного большими — даже всего несколько файлов — я обнаруживаю, что мне приходится охотиться за главными реализациями студентов.

Поэтому я рекомендую иметь класс Main (или какой-нибудь класс с «Main» в названии), единственной целью которого является размещение public static main метода. Создайте класс Main и поместите в него свой public static void main. Теперь вам и всем будет очевидно, где находится ваш метод main. И как бы ни росла ваша программа со временем, вам не придется переносить его из одного класса в другой, чтобы учесть этот рост. Должен заметить, что это не универсальная конвенция, хотя я готов поспорить, что мало кому она не понравится: она никогда не повредит и может помочь.

Это также хорошо согласуется с идеей, что main — это просто договорная точка входа. Классы должны что-то моделировать, и если вы последуете этому совету, то ваш класс Main будет моделировать, что он является точкой входа в вашу программу. Он рекламирует не более того, но он рекламирует, что его цель — разместить main (в отличие от имени Square). Таким образом, в нашем примере мы имеем:

// In Main.java
public class Main {
    public static void main(String args[]) {
        Square square = new Square();
        square.setSideLength(3.2f);
        System.out.println("The area of the square is " + square.getArea());
        System.out.println("The perimiter of the square is " + square.getPerimeter());
    }
}

Войти в полноэкранный режим Выйти из полноэкранного режима
// In Square.java
public class Square {
    private float sideLength = 0.0f;

    public void setSideLength(float length) {
        sideLength = length;
    }

    public float getArea() {
        return sideLength * sideLength;
    }

    public float getPerimeter() {
        return 4 * sideLength;
    }
}

Войти в полноэкранный режим Выйти из полноэкранного режима

Содержит ли main слишком много?

Здесь я буду более противоречив. Я думаю, что даже в этой версии main делает слишком много. Я бы предпочел, чтобы Main вызывал метод другого класса, который хорошо назван для выполнения работы по созданию нашего Square. Я бы хотел, чтобы в main было как можно меньше логики: он нужен для выполнения нашего контракта с Java и ни для чего другого. Все остальное, что мы делаем интересного, должно быть сделано в классе, целью которого является именно это. Я выступаю за то, чтобы сохранить этот контракт с Java отдельно от всего остального. Здесь я довольно экстремален. Я бы предпочел видеть что-то вроде

// In Main.java
public class Main {
    public static void main(String args[]) {
        Driver.startTheProgram();
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима
// In Driver.java
public class Driver {
    public static void startTheProgram() {
        Square square = new Square();
        square.setSideLength(3.2f);
        System.out.println("The area of the square is " + square.getArea());
        System.out.println("The perimiter of the square is " + square.getPerimeter());
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима
// In Square.java
public class Square {
    private float sideLength = 0.0f;

    public void setSideLength(float length) {
        sideLength = length;
    }

    public float getArea() {
        return sideLength * sideLength;
    }

    public float getPerimeter() {
        return 4 * sideLength;
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Теперь Main не делает ничего, кроме выполнения нашего контракта с Java runtime, Driver отвечает за нашу логику, как управлять нашей программой, а Square просто моделирует Square. Если мы хотим, чтобы наша программа делала больше, мы помещаем больше в Driver. Если мы передумаем, что делать первым, мы либо изменим реализацию Driver startTheProgram, либо создадим другой класс, который мы вызываем из main, чтобы сделать что-то первым, и пусть он вызывает Driver, и т.д.

Я должен признать следующее: вы найдете много людей, использующих классы Main или оценивших мою точку зрения о наличии отдельного класса Main; вы, вероятно, найдете меньше тех, кто будет рад моему созданию еще одного класса, такого как Driver, который вызывает main, особенно для небольших программ.

Оцените статью
devanswers.ru
Добавить комментарий