天天看點

結對程式設計與TDD結合開發實踐

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

訓練題目:機器人探查火星

結對程式設計與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));
		}
	}
}