ต่อจากตอนก่อนนะครับ

จาก comment ของคุณ deans4j ในหัวข้อสร้างชุดทดสอบนะครับ ผมได้ไป refactor มานะครับ

ส่วนแรกสังเกตว่าเรามีการสั่ง 1 + f/a หลายที จริง ๆ แล้วในส่วนดังกล่าวเราคำนวณจำนวนที่ a หารลงตั้งแต่ 0 ถึง f ผมเลยแยกออกมาเป็นเมท็อดใหม่ได้ดังด้านล่างครับ

(แก้อธิบายเพิ่มเติม หลังจะได้รับ comment จากคุณ deans นะครับ ในส่วนที่เขียนเพิ่ม ผมทำเป็นตัวสีน้ำเงินเข้มนะครับ)

ในส่วนแรกที่ผมทำ ผมสังเกตว่าเราสั่ง 1 + f/a หลายทีเหลือเกิน นึกไปนึกมาเรามีวิธีการในการคำนวณที่ตรงไปตรงมากกว่าวิธีเดิมดังนี้ครับ

สังเกตว่า ในการหาว่าในช่วงจาก f ถึง t มีกี่ตัวที่ a หารลงตัว จริง ๆ มันก็เหมือนกับการหาว่าในช่วงจาก 0 ถึง t มีกี่ตัวที่ a หารลงตัว แล้วลบออกด้วยจำนวนตัวที่ a หารลงตัวในช่วงจาก 0 ถึง f-1

ดังนั้นผมจึงคิดว่า เราควรจะแยกเมท็อดสำหรับการคำนวณดังกล่าวออกมาครับ ผมเรียกว่า countFromZero แสดงดังด้านล่างครับ (ซึ่งมีหน้าตาเหมือนกับการสั่ง 1 + f/a เลย)

	static int countFromZero(int a, int t) {
		return 1 + t/a;
	}

เนื่องจากเมท็อดดังกล่าวเป็นหัวใจสำคัญของการคำนวณของเรา ผมเลยเพิ่ม พร้อมกับใส่ test ไปอีกสองอัน ใน DivisibilityTest.java

	@Test
	public void testCountFromZero() {
		assertEquals(4, Divisibility.countFromZero(3, 10));
	}
	
	@Test
	public void testCountFromZeroDivisibleByA() {
		assertEquals(5, Divisibility.countFromZero(3, 12));
	}

พอแยก countFromZero ออกมาแล้ว ส่วนของเมท็อดหลักจะเปลี่ยนเป็น

	public static int countMultiplesInRange(int a, int f, int t) {
		if(f<0) {
			int shift = findShift(a,f);
			
			f += shift;
			t += shift;
		}
		if(f==0)
			return countFromZero(a,t);
		else
			return countFromZero(a,t) - countFromZero(a,f-1);
	}
สังเกตว่า เงื่อนไขเดิมที่ทดสอบว่า a หาร f ลงตัวหรือไม่ ถูกเอาออกไปแล้ว เพราะว่าไม่จำเป็น และโปรแกรมที่เราเขียนแสดงความตั้งใจที่ชัดเจนกว่าวิธีเดิม

ทีนี้สังเกตว่าเรามีการใช้เมท็อด findShift ผมก็เลยคิดว่าควรจะ test อีกหน่อย ของเก่ามันเป็นเมท็อดแบบ private ผมตัดออกเพื่อจะได้เรียกใช้ได้จาก unit test แล้วก็เพิ่ม testcase ไปสองอัน

	@Test
	public void testFindShiftNotDivisible() {
		int shift = Divisibility.findShift(3, -10);
		assertTrue(shift%3 == 0);
		assertTrue(-10 + shift >= 0);
	}
	
	@Test
	public void testFindShiftDivisible() {
		int shift = Divisibility.findShift(3, -12);
		assertTrue(shift%3 == 0);
		assertTrue(-12 + shift >= 0);
	}

สังเกตในส่วนของการ assertXX นะครับ ว่าเราไม่ได้ระบุว่า shift จะต้องเป็นอะไร แต่ว่าจะต้องหาร 3 ลงตัว และเมื่อบวกกับขอบช่วงด้านซ้ายแล้วต้องมีค่าไม่น้อยกว่าศูนย์

พอทดสอบว่าผ่าน unit test หมดแล้ว ผมกลับไปดู code อีกรอบแล้วก็แยกส่วนที่นับช่วงที่เป็นจำนวนบวกออกมา (เป็นเมท็อด countNonNegativeRange) สรุปได้เมท็อด countMultiplesInRange ดังด้านล่างครับ

	static int countNonNegativeRange(int a, int f, int t) {
		if(f==0)
			return countFromZero(a,t);
		else
			return countFromZero(a,t) - countFromZero(a,f-1);		
	}
	
	public static int countMultiplesInRange(int a, int f, int t) {
		if(f<0) {
			int shift = findShift(a,f);
			
			f += shift;
			t += shift;
		}
		return countNonNegativeRange(a,f,t);
	}

คราวหน้าถ้าไม่ดูส่วน parameterized test ครับ ก็อาจจะดูการใช้งาน EasyMock ครับ

Comment

Comment:

Tweet

ผมส่งเมลกลับให้แล้วนะครับ

#3 By deans4j (124.120.130.121) on 2008-09-08 14:28

คุณ deans4j ขอบคุณมากครับ เดี๋ยวเมล์ให้ครับ

#2 By wonam on 2008-09-08 07:33

อ.มะนาวครับ ถ้าไม่รังเกียจผมรบกวนขอ source ทั้งหมดได้ไหมครับ big smile

มีหลายส่วนที่ผมอยากจะแนะนำ แต่คิดว่าไม่สะดวกที่จะพิมพ์ลงตรงนี้ confused smile

ผมกะว่าจะแทรกคำแนะนำลงใน code เป็นจุดๆ ไปน่าจะให้ได้รายละเอียดที่มากกว่า

อีเมลผมก็ชื่อนี้ ณ ยาhoo จุดคอm big smile

#1 By deans4j (124.120.130.121) on 2008-09-08 03:17