BadDesign: іменуємо параметри в Java

У деяких мовах програмування (наприклад, 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));


Плюси
  • Не помилитися з зазначенням висоти і ширини, якщо використовувати конструктор з обгортками.


Мінуси
  • Занадто багато класів.
  • Багатослівно.
  • Все ще не можна змінювати порядок вказівки значень параметрів.


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.