結對編譯與TDD結合的方式是:首先,第一個人寫一個失敗的單元測試,第二個人寫代碼讓這個單元測試通過,然後第二個人再寫一個失敗的單元測試,交給第一個人,他再寫代碼讓其通過...依次交替,直至完成。寫代碼之前或完成編碼單元測試通過後都可對代碼進行重構。
訓練題目:機器人探查火星

RobotTest.java
package com.study.robot.test;
import org.junit.Assert;
import org.junit.Test;
import com.study.robot.ControlCenter;
import com.study.robot.Position;
import com.study.robot.Robot;
public class RobotTest {
@Test
public void test_turn_left() {
Position position = new Position(0, 0, "N");
Robot robot = new Robot(position);
robot.command("L");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(0, 0, "W"), resultPosition);
}
@Test
public void test_turn_right() {
Position position = new Position(0, 0, "N");
Robot robot = new Robot(position);
robot.command("R");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(0, 0, "E"), resultPosition);
}
@Test
public void test_when_given_0_0_S_position_turn_right() {
Position position = new Position(0, 0, "S");
Robot robot = new Robot(position);
robot.command("R");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(0, 0, "W"), resultPosition);
}
@Test
public void test_when_given_0_0_S_position_and_turn_twice() {
Position position = new Position(0, 0, "S");
Robot robot = new Robot(position);
robot.command("R");
robot.command("R");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(0, 0, "N"), resultPosition);
}
@Test
public void test_when_given_0_0_N_move_and_no_turn() {
Position position = new Position(0, 0, "N");
Robot robot = new Robot(position);
robot.command("M");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(0, 1, "N"), resultPosition);
}
@Test
public void test_when_given_0_0_E_move_and_no_turn() {
Position position = new Position(0, 0, "E");
Robot robot = new Robot(position);
robot.command("M");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(1, 0, "E"), resultPosition);
}
@Test
public void test_when_given_0_0_S_move_then_return_0_0_S() {
Position position = new Position(0, 0, "S");
Robot robot = new Robot(position);
robot.command("M");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(0, 0, "S"), resultPosition);
}
@Test
public void test_when_given_0_3_W_move_then_return_2_3_N() {
Position position = new Position(0, 3, "W");
Robot robot = new Robot(position);
robot.command("M");
robot.command("R");
robot.command("R");
robot.command("M");
robot.command("M");
robot.command("L");
Position resultPosition = robot.position;
Assert.assertEquals(new Position(2, 3, "N"), resultPosition);
}
@Test
public void test_two_robots() {
Position position = new Position(0, 0, "E");
Robot robot1 = new Robot(position);
Robot robot2 = new Robot(position);
ControlCenter controlCenter = new ControlCenter();
controlCenter.addRobots(robot1);
controlCenter.addRobots(robot2);
controlCenter.command("M");
Assert.assertEquals(new Position(1, 0, "E"), robot1.position);
Assert.assertEquals(new Position(1, 0, "E"), robot2.position);
}
@Test
public void test_two_robots_turn_left_and_move() {
Position position = new Position(0, 0, "E");
Robot robot1 = new Robot(position);
Robot robot2 = new Robot(position);
ControlCenter controlCenter = new ControlCenter();
controlCenter.addRobots(robot1);
controlCenter.addRobots(robot2);
controlCenter.command("L");
controlCenter.command("M");
Assert.assertEquals(new Position(0, 1, "N"), robot1.position);
Assert.assertEquals(new Position(0, 1, "N"), robot2.position);
}
}
Position.java
package com.study.robot;
public class Position {
public int x;
public int y;
public String direction;
public Position(int x, int y, String direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
public Position(){
super();
}
@Override
public boolean equals(Object object) {
Position position = (Position)object;
if(x != position.x){
return false;
}
if(y != position.y){
return false;
}
if(!direction.equals(position.direction)){
return false;
}
return true;
}
public void operateX(Integer opx){
if(opx == null) {
return;
}
if(this.x == 0 && opx < 0) {
return;
}
this.x += opx;
}
public void operateY(Integer opy) {
if(opy == null) {
return;
}
if(this.y == 0 && opy < 0) {
return;
}
this.y += opy;
}
}
ControlCenter.java
package com.study.robot;
import java.util.ArrayList;
import java.util.List;
/**
* 采用指令模式實作
*/
public class ControlCenter {
private List<Robot> robots = new ArrayList<Robot>();
public void addRobots(Robot robot) {
robots.add(robot);
}
public void command(String command) {
for(Robot robot: robots) {
robot.command(command);
}
}
}
Robot.java
package com.study.robot;
import java.util.HashMap;
import java.util.Map;
/**
* 表驅動法實作指令的執行
* 表驅動法是一種程式設計模式——從表中查找資訊而不是使用邏輯語句(if或else)。如果邏輯很複雜,導緻邏輯判斷鍊很長,使用驅動表法有助于降低複雜度。否則,表驅動法隻會增加複雜度。
* 從表中查詢條目有三種方法:
* a.直接通路(Directory access)表
* b.索引通路(Index access)表
* c.階梯通路(Stair-step access)表
* 表中儲存的可能是資料、函數指針,對象執行個體等(說明:如果儲存的是對象執行個體的話,那就是指令模式)
*/
public class Robot {
public Position position;
private String DIRECTION_EAST = "E";
private String DIRECTION_WEST = "W";
private String DIRECTION_SOUTH = "S";
private String DIRECTION_NORTH = "N";
private String COMMAND_LEFT = "L";
private String COMMAND_RIGHT = "R";
private String COMMAND_MOVE = "M";
Map<String,String> directionSearchTable = new HashMap<String,String>(){{
put(DIRECTION_EAST+COMMAND_LEFT, DIRECTION_NORTH);
put(DIRECTION_WEST+COMMAND_LEFT, DIRECTION_SOUTH);
put(DIRECTION_SOUTH+COMMAND_LEFT, DIRECTION_EAST);
put(DIRECTION_NORTH+COMMAND_LEFT, DIRECTION_WEST);
put(DIRECTION_EAST+COMMAND_RIGHT, DIRECTION_SOUTH);
put(DIRECTION_WEST+COMMAND_RIGHT, DIRECTION_NORTH);
put(DIRECTION_SOUTH+COMMAND_RIGHT, DIRECTION_WEST);
put(DIRECTION_NORTH+COMMAND_RIGHT, DIRECTION_EAST);
}};
Map<String,Integer> xSearchTable = new HashMap<String,Integer>(){{
put(DIRECTION_EAST, new Integer(1));
put(DIRECTION_WEST, new Integer(-1));
}};
Map<String,Integer> ySearchTable = new HashMap<String,Integer>(){{
put(DIRECTION_SOUTH, new Integer(-1));
put(DIRECTION_NORTH, new Integer(1));
}};
public Robot(Position position) {
this.position = new Position();
this.position.x = position.x;
this.position.y = position.y;
this.position.direction = position.direction;
}
public void command(String command) {
if(command.equals(COMMAND_LEFT) || command.equals(COMMAND_RIGHT)) {
position.direction = directionSearchTable.get(position.direction+command);
}
if(command.equals(COMMAND_MOVE)){
position.operateX(xSearchTable.get(position.direction));
position.operateY(ySearchTable.get(position.direction));
}
}
}