powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Как отрефакторить?
18 сообщений из 18, страница 1 из 1
Как отрефакторить?
    #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
Как отрефакторить?
    #38745154
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Даже живой дядя Вася тракторист не будет залогом того
Dymytry, чтобы заложить максимальную гибкость для дальнейшего развития.
А уж любая программа будет ему сливать в разы.

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


шозабред
...
Рейтинг: 0 / 0
Как отрефакторить?
    #38745287
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
Как отрефакторить?
    #38745301
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scf,

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

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

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

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

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

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

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

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

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

2) можно передвигать юниты изнутри. То есть через unit.moveForward(..). Однако получаем большую связанность между объектами: юниту надо провайдить например рельеф, может другие юниты.. непонятно как это красиво написать. Есть вещи, от которых зависит ход юнита, но которых в нем быть не должно - ямы на земле, погода, соседние юниты..
...
Рейтинг: 0 / 0
Как отрефакторить?
    #38745432
pirovindos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИМХО. Исходная прикладная задача - это тот редкий и классический случай, когда парадигма ООП не очень хороша для всей задачи целиком, но извернуться и сделать можно, в том числе, используя и ООП для части задачи.
...
Рейтинг: 0 / 0
Как отрефакторить?
    #38745433
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
pirovindosИМХО. Исходная прикладная задача - это тот редкий и классический случай, когда парадигма ООП не очень хороша для всей задачи целиком, но извернуться и сделать можно, в том числе, используя и ООП для части задачи.
ИМХО, ерунда. Во-первых, случай не редкий. Конечно, через Scala всё было бы проще и красивее.
Во-вторых даже парадигма ООП здесь вполне подходит. Задача - показать и научить реализовывать очень распространенный прием рефакторинга, который знают, к сожалению, далеко не все.
...
Рейтинг: 0 / 0
Как отрефакторить?
    #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
Как отрефакторить?
    #38745572
DDiver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

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

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

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

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


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