В некоторых языках программирования (например, в Scala) есть именованные параметры. Именованные параметры позволяют контролировать присвоение значений, дополнительным бонусом выступает возможность использовать свой порядок указания параметров, нежели описано в сигнатуре функции. В рамках цикла статей BadDesign, предложу урезанный механизм именованных параметров для Java.
Следующий пример демонстрирует описанный механизм именованных параметров.
Пусть есть функция, которая печатает имя и фамилию.
def printName(first:String, last:String) = {
println(first + " " + last)
}
Вызов функции без использования именованных параметров:
printName("John","Smith")
// Prints "John Smith"
Вызов функции с именованными параметрами:
printName(first = "John",last = "Smith")
// Prints "John Smith"
Вызов функции с именованными параметрами и измененным порядком указания параметров:
printName(last = "Smith",first = "John")
// Prints "John Smith"
Рассмотрим класс прямоугольник с двумя полями: ширина и высота. Дополнительно предположим, что прямоугольники используются где-то в приложении и имеют дефолтные значения для ширины и высоты.
Простой пример реализации мог бы выглядеть так:
public class Rectangle {
public static final int DEFAULT_HEIGHT = 50;
public static final int DEFAULT_WIDTH = 200;
private int height;
private int width;
public Rectangle() {
this(DEFAULT_HEIGHT, DEFAULT_WIDTH);
}
public Rectangle(int height, int width) {
this.height = height;
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
Далее рассмотрим несколько примеров.
// Создание прямоугольника с дефолтными значениями для высоты и ширины.
Rectangle rectangle = new Rectangle();
// Создание прямоугольника с указанными значениями для высоты и ширины.
Rectangle rectangle = new Rectangle(27, 109);
// Создание прямоугольника с дефолтным значением для ширины и указанным значением для высоты.
Rectangle rectangle = new Rectangle();
rectangle.setHeight(27);
// Создание прямоугольника с дефолтным значением для высоты и указанным значением для ширины.
Rectangle rectangle = new Rectangle();
rectangle.setWidth(109);
Было бы очень здорово, если можно было бы использовать только конструктор для выполнения выше указанных операций, т.е. хочется что-то типа такого:
public class Rectangle {
...
public Rectangle(int height) {
this(height, DEFAULT_WIDTH);
}
public Rectangle(int width) {
this(DEFAULT_HEIGHT, width);
}
...
}
Однако, такой код не компилируется в Java (что, в общем-то, логично).
Обойти эту проблему можно создав маленькие обертки над высотой и шириной.
Обертка над высотой:
public class RectangleHeight {
private int height;
private RectangleHeight(int height) {
this.height = height;
}
public static RectangleHeight rectangleHeight(int height) {
return new RectangleHeight(height);
}
public int getValue() {
return height;
}
}
Обертка над шириной:
class RectangleWidth {
private int width;
private RectangleWidth(int width) {
this.width = width;
}
public static RectangleWidth rectangleWidth(int width) {
return new RectangleWidth(width);
}
public int getValue() {
return width;
}
}
Теперь добавим в класс Rectangle два конструктора:
public class Rectangle {
...
public Rectangle(RectangleHeight rectangleHeight) {
this(rectangleHeight.getValue(), DEFAULT_WIDTH);
}
public Rectangle(RectangleWidth rectangleWidth) {
this(DEFAULT_HEIGHT, rectangleWidth.getValue());
}
...
}
Теперь есть некая имитация именованных параметров.
Вместо
// Создание прямоугольника с дефолтным значением для ширины и указанным значением для высоты.
Rectangle rectangle = new Rectangle();
rectangle.setHeight(27);
теперь можно сделать так:
// Создание прямоугольника с дефолтным значением для ширины и указанным значением для высоты.
Rectangle rectangle = new Rectangle(rectangleHeight(27));
Вместо:
// Создание прямоугольника с дефолтным значением для высоты и указанным значением для ширины:
Rectangle rectangle = new Rectangle();
rectangle.setWidth(109);
теперь можно сделать так:
// Создание прямоугольника с дефолтным значением для высоты и указанным значением для ширины:
Rectangle rectangle = new Rectangle(rectangleWidth(100));
Вместо:
// Создание прямоугольника с указанными значениями для высоты и ширины.
Rectangle rectangle = new Rectangle(27, 109);
теперь можно сделать так:
// Создание прямоугольника с указанными значениями для высоты и ширины.
Rectangle rectangle = new Rectangle(rectangleHeight(27), rectangleWidth(109));
Плюсы
- Нельзя ошибиться с указанием высоты и ширины, если использовать конструктор с обертками.
Минусы
- Слишком много классов.
- Многословно.
- Всё еще нельзя менять порядок указания значений параметров.
Автор: jxcoder