В предыдущей части мы рассмотрели как избавиться от if в паттерне "фабричный метод". Но есть паттерны специально придуманные чтобы избавить вас от этой проблемы. Один из них паттерн "Состояние".
Рассмотрим небольшой пример. У нас есть класс Tractor, у которого есть состояние: Ориентация по стороне света и координаты. У трактора есть возможность повернуться(метод turn) и двигаться в этом направлении (метод move).
Обычно решение в лоб вырождается в портянку if-else в зависимости от некоторого состояния. В нашем случае состояние представляет собой направление движения, т.е. ориентацию по стороне света. Для того чтобы решить эту проблему выделим интерфейс состояния. Он будет представлять собой следующее:
Смотрите, логика переходов по состояниям у нас теперь находится в специальных классах. И класс Tractor теперь просто должен делегировать свои действия текущему состоянию. Обратите внимание, что меняет состояние только метод turn. Таким образом итоговый код класса Tractor вырождается в следующее:
Рассмотрим небольшой пример. У нас есть класс Tractor, у которого есть состояние: Ориентация по стороне света и координаты. У трактора есть возможность повернуться(метод turn) и двигаться в этом направлении (метод move).
package com.bssys.blog;
public class Tractor {
public Orientation currentOrientation;
public Coordinate currentCoordinate;
public Tractor() {
currentOrientation = Orientation.North;
currentCoordinate = new Coordinate(0, 0);
}
public Tractor(Orientation currentOrientation, Coordinate currentCoordinate) {
this.currentOrientation = currentOrientation;
this.currentCoordinate = currentCoordinate;
}
public void move() {
if (currentOrientation == Orientation.North) {
currentCoordinate.y = currentCoordinate.y + 1;
} else if (currentOrientation == Orientation.South) {
currentCoordinate.y = currentCoordinate.y - 1;
} else if (currentOrientation == Orientation.West) {
currentCoordinate.x = currentCoordinate.x - 1;
} else if (currentOrientation == Orientation.East) {
currentCoordinate.x = currentCoordinate.x + 1;
}
}
public void turn() {
if (currentOrientation == Orientation.North) {
currentOrientation = Orientation.East;
} else if (currentOrientation == Orientation.South) {
currentOrientation = Orientation.West;
} else if (currentOrientation == Orientation.West) {
currentOrientation = Orientation.North;
} else if (currentOrientation == Orientation.East) {
currentOrientation = Orientation.South;
}
}
public Orientation getCurrentOrientation() {
return currentOrientation;
}
public Coordinate getCurrentCoordinate() {
return currentCoordinate;
}
@Override
public String toString() {
return "" + currentOrientation + " " + currentCoordinate;
}
}
class Coordinate {
public int x;
public int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "x=" + x + " " + "y=" + y;
}
}
enum Orientation {
North, South, West, East
}
Обычно решение в лоб вырождается в портянку if-else в зависимости от некоторого состояния. В нашем случае состояние представляет собой направление движения, т.е. ориентацию по стороне света. Для того чтобы решить эту проблему выделим интерфейс состояния. Он будет представлять собой следующее:
interface State {
public void turn(Tractor tractor);
public void move();
}
Реализуем этот интерфейс для всех наших возможных состояний, и добавим в класс Tractor поле хранящее текущее состояние согласно нашему паттерну:
class EastState implements State {
private Coordinate coordinate;
public EastState(Coordinate coordinate) {
this.coordinate = coordinate;
}
public void turn(Tractor tractor) {
tractor.setCurrentState(new SouthState(coordinate));
}
public void move() {
coordinate.x = coordinate.x + 1;
}
@Override
public String toString() {
return "East:" + coordinate;
}
}
class NorthState implements State {
private Coordinate coordinate;
public NorthState(Coordinate coordinate) {
this.coordinate = coordinate;
}
public void turn(Tractor tractor) {
tractor.setCurrentState(new EastState(coordinate));
}
public void move() {
coordinate.y = coordinate.y + 1;
}
@Override
public String toString() {
return "North:" + coordinate;
}
}
class SouthState implements State {
private Coordinate coordinate;
public SouthState(Coordinate coordinate) {
this.coordinate = coordinate;
}
public void turn(Tractor tractor) {
tractor.setCurrentState(new WestState(coordinate));
}
public void move() {
coordinate.y = coordinate.y - 1;
}
@Override
public String toString() {
return "South:" + coordinate;
}
}
class WestState implements State {
private Coordinate coordinate;
public WestState(Coordinate coordinate) {
this.coordinate = coordinate;
}
public void turn(Tractor tractor) {
tractor.setCurrentState(new NorthState(coordinate));
}
public void move() {
coordinate.x = coordinate.x - 1;
}
@Override
public String toString() {
return "West:" + coordinate;
}
}
Смотрите, логика переходов по состояниям у нас теперь находится в специальных классах. И класс Tractor теперь просто должен делегировать свои действия текущему состоянию. Обратите внимание, что меняет состояние только метод turn. Таким образом итоговый код класса Tractor вырождается в следующее:
public class Tractor {
private State currentState;
public Tractor() {
currentState = new NorthState(new Coordinate(0, 0));
}
public void move() {
currentState.move();
}
public void turn() {
currentState.turn(this);
}
public void setCurrentState(State state) {
this.currentState = state;
}
@Override
public String toString() {
return currentState.toString();
}
public static void main(String[] args) {
Tractor tractor = new Tractor();
System.out.println(tractor);
tractor.turn();
tractor.move();
tractor.move();
tractor.move();
System.out.println(tractor);
tractor.turn();
tractor.move();
tractor.move();
tractor.move();
System.out.println(tractor);
}
}
1 комментарий:
Casino City - MapYRO
Casino City. Casino 문경 출장마사지 City. 양산 출장샵 Mapyro® 시흥 출장마사지 is 순천 출장안마 a fun and friendly community place. Find a table game floor, live music and free WiFi 수원 출장마사지 in rooms and suites.
Отправить комментарий