Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Как отрефакторить? / 18 сообщений из 18, страница 1 из 1
12.09.2014, 14:16
    #38745137
Dymytry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Есть такой тест на знание ООП, называется Iffy Tractor. Задача в том, что есть некая компьютерная игра, управляющая трактором через команды-строки, и надо это дело отрефакторить так, чтобы заложить максимальную гибкость для дальнейшего развития.

Вот код класса который надо отрефакторить: http://pastebin.com/s3ABaBqh.

Идея взята отсюда: http://www.benstopford.com/2011/05/11/the-iffy-tractor-can-they-code-oo/

В будущем возможны модификации:
1. разные типы юнитов
2. другие типы действий, зависящие от типа юнита
3. логгирование всех действий юнитов

Как бы вы это сделали? Если лень писать - а ведь это пятница - то вот мое решение, просьба его злостно обличить.

-----

Очевидная вещь - избавиться от if-blocks с направлениями через вектора. Это понятно. Далее:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
    public interface Unit {
    }
    public interface Land {
        void positionUnit(Unit unit, Location location, Orientation orientation);
        Orientation getUnitOrientation(Unit unit);
        Location getUnitLocation(Unit unit);
    }
    /** to beinjected in Land instance **/
    public interface Landscape {
        boolean isAvailable(Location location);
    }
    public interface GameOperator {
        public void runCommand(String command, Unit unit);
    }



Landscape инжектится в Land.

Как реализовать транляцию строки-команды в действие Трактора внутри `GameOperator`?

1. Простой if-block который, поняв что за команда, рассчитывает позицию Трактора и ставит его в Land через via `setPosition(..)`.

2. Сделать интерфейс Action для единичного действия. Делать новый объект для каждой команды, или "штамповать" объекты из пула нужными параметрами. Все равно if-block. Пример:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
    public class Move implements Action {
        private Land land;
        private Unit unit;    
        public Move(Unit unit, Land land) {
            this.land = land;
            this.unit = unit;
        }    
        @Override
        public void evaluate() {
            Location oldLocation = land.getUnitLocation(unit);
            Orientation oldOrientation = land.getUnitOrientation(unit);
            Location newLocation = new Location(oldLocation.getX() + oldOrientation.getX(), oldLocation.getY() + oldOrientation.getY());
            land.positionUnit(unit, newLocation, oldOrientation);
        }
    }



Ваше авторитетное мнение!
...
Рейтинг: 0 / 0
12.09.2014, 14:30
    #38745154
Сергей Арсеньев
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Даже живой дядя Вася тракторист не будет залогом того
Dymytry, чтобы заложить максимальную гибкость для дальнейшего развития.
А уж любая программа будет ему сливать в разы.

Сформулируйте критерии гибкости и пороги пожалуйста.
...
Рейтинг: 0 / 0
12.09.2014, 15:09
    #38745243
scf
scf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Код: java
1.
if(position[0]>field[0]||position[1]>field[1]){


шозабред
...
Рейтинг: 0 / 0
12.09.2014, 15:33
    #38745287
scf
scf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Рефакторинг обычно подразумевает неизменность API, так что решить полноценно эту задачу нельзя. Если API сохранять неизменным, то получится вот что:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
public class Tractor {

	private Point position = new Point(0, 0);
	private int fieldSizeX = 5;
	private int fieldSizeY = 5;
	private Vector orientation = new Vector(0, -1);
	
	private static final String[] ORIENTATION = new String[] {
		" ", "N", " ",
		"W", " ", "E",
		" ", "S", " "
	};
	
	public void move(String command) {
		if(command=="F"){
			moveForwards();
		}else if(command=="T"){
			turnClockwise();
		}
	}
	
	public int getPositionX() {
		return position.x;
	}

	public int getPositionY() {
		return position.y;
	}

	public String getOrientation() {
		return ORIENTATION[position.x + 1 + (position.y + 1) * 3 ];
	}

	private void moveForwards() {
		Point newPosition = position.add(orientation);
		
		if (!newPosition.in(0, 0, fieldSizeX - 1, fieldSizeY - 1)) {
			throw new TractorInDitchException();
		}
		position = newPosition;
	}

	private void turnClockwise() {
		orientation = orientation.rotateClockwise90();
	}
	
	private static class Vector {
		public final int x, y;
		public Vector(int x, int y) {
			this.x = x;
			this.y = y;
		}
		public Vector rotateClockwise90() {
			return new Vector(-y, x);
		}
	}
	
	private static class Point {
		public final int x, y;
		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}
		
		public Point add(Vector v) {
			return new Point(x + v.x, y + v.y);
		}
		
		public boolean in(int x1, int y1, int x2, int y2) {
			return x >= x1 && x <= x2 && y >= y1 && y <= y2;
		}
	}
}
...
Рейтинг: 0 / 0
12.09.2014, 15:39
    #38745301
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
scf,

Команды тоже надо рефакторить.
...
Рейтинг: 0 / 0
12.09.2014, 15:42
    #38745308
scf
scf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Blazkowicz,

В рамках текущего API и текущего набора команд нет смысла... разве что == на equals заменить :-)
...
Рейтинг: 0 / 0
12.09.2014, 15:45
    #38745311
scf
scf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Dymytry,

Когда реализуешь все свои идеи, посмотри на результат.
Сравни количество букв.
Пойми, какой код будет проще понять и расширить - твой или исходный.
...
Рейтинг: 0 / 0
12.09.2014, 15:46
    #38745312
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
scfBlazkowicz,

В рамках текущего API и текущего набора команд нет смысла... разве что == на equals заменить :-)
В рамках текущего кода вообще рефакторить нет смысла. Задача на будущее расширение во всех смыслах. В том числи и команд.
...
Рейтинг: 0 / 0
12.09.2014, 15:50
    #38745315
scf
scf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Blazkowicz,

В таких случаях я обычно предлагаю отложить рефакторинг до момента, когда *действительно* появится необходимость что-то менять :)

Текущую реализацию можно обвинять в чем угодно, но точно не в излишней сложности. К тому же, в исходном задании есть юнит-тест на этот API, так что аккуратно надо
...
Рейтинг: 0 / 0
12.09.2014, 15:54
    #38745322
Dymytry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
scf,
считаем что указанные выше модификации

авторВ будущем возможны модификации:
1. разные типы юнитов
2. другие типы действий, зависящие от типа юнита
3. логгирование всех действий юнитов

- уже дописываются аналитиками :)
...
Рейтинг: 0 / 0
12.09.2014, 16:20
    #38745348
Dymytry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Тут какой вопрос главный.

1) можно передвигать юниты снаружи. Так как сделал я, можно через land.moveUnitForward(unit). Юниты двигает сам Land или некий оператор. Тут слабая связанность, и поэтому такой подход мне больше нравится, хотя моя реализация плохая.

2) можно передвигать юниты изнутри. То есть через unit.moveForward(..). Однако получаем большую связанность между объектами: юниту надо провайдить например рельеф, может другие юниты.. непонятно как это красиво написать. Есть вещи, от которых зависит ход юнита, но которых в нем быть не должно - ямы на земле, погода, соседние юниты..
...
Рейтинг: 0 / 0
12.09.2014, 17:18
    #38745432
pirovindos
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
ИМХО. Исходная прикладная задача - это тот редкий и классический случай, когда парадигма ООП не очень хороша для всей задачи целиком, но извернуться и сделать можно, в том числе, используя и ООП для части задачи.
...
Рейтинг: 0 / 0
12.09.2014, 17:21
    #38745433
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
pirovindosИМХО. Исходная прикладная задача - это тот редкий и классический случай, когда парадигма ООП не очень хороша для всей задачи целиком, но извернуться и сделать можно, в том числе, используя и ООП для части задачи.
ИМХО, ерунда. Во-первых, случай не редкий. Конечно, через Scala всё было бы проще и красивее.
Во-вторых даже парадигма ООП здесь вполне подходит. Задача - показать и научить реализовывать очень распространенный прием рефакторинга, который знают, к сожалению, далеко не все.
...
Рейтинг: 0 / 0
12.09.2014, 19:59
    #38745571
Dymytry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Можно через Visitor Pattern.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
public interface Action {
    void run(Tractor unit);
    void run(Tank unit);
}
public interface Unit {
    void evaluate(Action action);
}

public class Main {
    public static void main(String[] args) {
       Unit unit = new Tractor();
       Action a = new MoveForwardAction();
       unit.evaluate(a);

       Unit tank = new Tank();
       tank.evaluate(a);
    }
}



Это удобно. Однако придется писать для каждой action реализации методов для всех типов Unit. Что конечно печально. Либо наоборот - для каждого Unit все типы Action.
...
Рейтинг: 0 / 0
12.09.2014, 20:04
    #38745572
DDiver
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Blazkowicz,

а что за приём? очень хотелось бы узнать
...
Рейтинг: 0 / 0
12.09.2014, 21:27
    #38745635
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
DDiverBlazkowicz,

а что за приём? очень хотелось бы узнать
По ссылке из вопроса:
"Replace Conditional with Polymorphism"
...
Рейтинг: 0 / 0
12.09.2014, 23:19
    #38745686
schwa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
Если уж говорить прямо, то каждое решение, использующее типовые приемы ООП и всяких рефакторингов из Мартинов Фаулеров, вообще не масштабируется в игровой предметной области т.к. они плохо справляются с высокой сложностью связей и количествами типов взаимодействий между игровыми объектами.

Если интересно как эта проблема будет решаться в настоящей игре, гуглите Game Component Hierarchy.
...
Рейтинг: 0 / 0
13.09.2014, 11:24
    #38745857
scf
scf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как отрефакторить?
schwa,

Вот +1.
Выскажу два соображения:
- чем сложнее объектная модель, тем прочнее она прибита гвоздями к тому, как ее задумывал использовать проектировщик.
- было дело, я ковырял исходники крупной браузерной MMORPG. Там рулит подход "данные отдельно, алгоритмы обработки данных отдельно".
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Как отрефакторить? / 18 сообщений из 18, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]