Center
of Excellence
Bài
2
Phân
loại kết quả xét tuyển
Qua bài toán phân
loại xét tuyển, bài viết sẽ trình bày kỹ thuật loại
bỏ (refactoring) tình trạng trùng lặp mã (code duplication)
bên trong một trang web dùng công nghệ JSF.
I.
Bài toán
Kết
quả xét tuyển vào Học viện SaigonTech của một thí sinh
bao gồm ba điểm: toán (math), viết luận (essay), và phỏng
vấn (interview). Các điểm này được chấm trên thang số
nguyên từ 0 đến 100. Hãy phát triển một web application
để phân loại (grade) kết quả xét tuyển cho một thí
sinh, biết rằng kết quả này được tính dựa trên điểm
trung bình (average) của ba môn như sau
- Loại A nếu average từ 90.0 trở lên,
- Loại B nếu average từ 80.0 đến dưới 90.0,
- Loại C nếu average từ 70.0 đến dưới 80.0,
- Loại D nếu average từ 60.0 đến dưới 70.0, và
- Loại F nếu average dưới 60.0
Dưới
đây là UI screen mẫu.
Hình
1
II.
Giải pháp
Vận
dụng qui trình giải quyết vấn đề như ở bài trước,
trước tiên ta thiết kế
một UI screen tĩnh dùng ngôn ngữ thuần XHTML, sau đó dùng
JSF để bổ sung phần động, tức phần tương tác với
user, rồi phát triển code tính toán.
1.
Thiết kế UI screen
Trong
NetBeans, tạo project mới với tên ScoresJSF
rồi thiết kế index.xhtml
như sau
2.
Bổ sung phần động cho UI screen
2.1.
Tạo managed bean
Dựa
vào yêu cầu bài toán và UI screen, ta xác định UI
components nào là input và đâu là output. Do user phải nhập
ba điểm số là math, essay, và interview, nên đây là ba
input components. Grade là kết quả cần được hiển thị,
nên grade là một output component. Từ đó ta có thiết kế
sơ bộ cho managed bean.
Sau
khi đã có thiết kế sơ bộ, ta tiến hành tạo managed
bean với phạm vi hoạt động (scope) là request.
(Các chọn lựa khác cho scope sẽ được trình bày trong
các bài tiếp theo, vào thời điểm thuận tiện. Lúc này,
request
là chọn lựa phù hợp.)
Hình
4
Kế
đến, ta bổ sung vào managed bean các fields cùng
getter/setter tương ứng. Đối với input fields, ta cần phát
sinh cả getter và setter. Tuy nhiên, đối với output field,
chỉ có getter là cần thiết.
2.2.
Tạo methods cho buttons
Bên
trong managed bean, ta tạo hai methods ứng với Grade
button và Clear button của UI screen. Lưu ý là lúc này managed bean vừa có
một field tên là grade,
vừa có một method với tên tương tự.
2.3.
Ràng buộc UI screen với managed
bean
Chi
tiết của phần này tương tự như bài trước.
3.
Phát triển code tính toán
3.1.
Design
3.2.
Test class
package model;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ScoresTest {
private Scores scores1 = new Scores(0, 0, 0);
private Scores scores2 = new Scores(50, 50, 50);
private Scores scores3 = new Scores(100, 100, 100);
@Test
public void grade() {
assertEquals('F', this.scores1.grade());
assertEquals('F', this.scores2.grade());
assertEquals('D', new Scores(60, 60, 60).grade());
assertEquals('D', new Scores(65, 65, 65).grade());
assertEquals('C', new Scores(70, 70, 70).grade());
assertEquals('C', new Scores(75, 75, 75).grade());
assertEquals('B', new Scores(80, 80, 80).grade());
assertEquals('B', new Scores(85, 85, 85).grade());
assertEquals('A', new Scores(90, 90, 90).grade());
assertEquals('A', new Scores(95, 95, 95).grade());
assertEquals('A', this.scores3.grade());
}
@Test
public void average() {
assertEquals(0.0, this.scores1.average(), 0.0);
assertEquals(50.0, this.scores2.average(), 0.0);
assertEquals(100.0, this.scores3.average(), 0.0);
}
@Test
public void sum() {
assertEquals(0, this.scores1.sum());
assertEquals(150, this.scores2.sum());
assertEquals(300, this.scores3.sum());
}
}
3.3.
Main class
package model;
public class Scores {
private int math;
private int essay;
private int interview;
public Scores(int math, int essay, int interview) {
this.math = math;
this.essay = essay;
this.interview = interview;
}
int sum() {
return this.math + this.essay + this.interview;
}
double average() {
return this.sum() / 3.0;
}
public char grade() {
double average = this.average();
if (average >= 90.0)
return 'A';
else if (average >= 80.0)
return 'B';
else if (average >= 70.0)
return 'C';
else if (average >= 60.0)
return 'D';
else
return 'F';
}
}
4.
Kết nối managed
bean với model
Hình
9
5.
Kiểm tra tính hợp lệ của dữ liệu nhập
5.1. Xử lý
trường hợp để trống ô nhập
Hình
10
Nhận
xét rằng tình trạng code duplication đã diễn ra trong
index.xhtml nên ta cần refactor. Tuy nhiên, trước mắt
ta cần xử lý trường hợp nhập sai data, tức trường
hợp user nhập data không phải là số nguyên từ 0 đến
100.
5.2. Xử lý
trường hợp nhập data không đúng yêu cầu
Hình
11
Đến
đây, trước khi refactor, ta cần thi hành application và kiểm
thử để chắc chắn rằng application hoạt động tốt.
6.
Refactor index.xhtml
Khác
với code duplication trong Java code, đây là tình huống code
duplication trong XHTML file. Trước tiên, ta cần nhận diện
những đoạn code nào rất giống nhau. Hình dưới đây
đánh dấu các khối tương tự, bao gồm những tags
<label>, <h:inputText>, <h:message>,
và <br/>. Tất nhiên trong mỗi khối sẽ có một
số chi tiết khác nhau. Ta cũng cần nhận diện chính xác
các chi tiết khác nhau này.
Hình
12
6.1.
Tách khối bằng cách tạo composite component
Sau
đây ta sẽ tách khối bằng cách tạo một thành phần
chuyên biệt gọi là composite component. Đây là thành phần
phức hợp, qui tụ nhiều thành phần đơn lẻ lại với
nhau, và được đặt cho một tên, để từ đó về sau,
ta có thể sử dụng component này bất kỳ khi nào ta muốn.
Trong
NetBeans, right-click vào project node, chọn New, rồi
chọn Other... để chuyển sang New File window.
Hình
13
Chọn
JavaServer Faces ở bảng Categories: bên trái, sau
đó chọn JSF Composite Component ở bảng File Types:
bên phải, rồi click Next để chuyển sang bước đặt
tên và xác định vị trí lưu trữ (Name and Location).
Hình
14
Nhập
inputScore
vào ô File
Name:,
nhập resources/sgt
vào ô Folder:,
rồi click Finish.
Khi đó NetBeans sẽ tạo một file mới với tên
inputScore.xhtml.
Hình
15
Hình
16
6.2.
Khai báo attributes cho composite component
Đến
đây ta tiến hành khai báo attributes cho composite component
bên trong <cc:interface> tag. Số lượng attributes
là số lượng các chi tiết khác nhau trong từng khối, như
đã được nhận diện ở trên. Chúng bao gồm tên môn thi
(subject) bên trong <label> tag và điểm số
(score) của value attribute bên trong <h:inputText>.
Ta khai báo như sau
Hình
17
6.3.
Định nghĩa khối bên trong composite component
Sau
khi đã khai báo attributes, ta đặt khối vào
<cc:implementation> tag, rồi thay các chi tiết khác
nhau trong khối bằng tên của attributes. Cần lưu ý qui ước
về cách sử dụng attributes: #{cc.attrs.???}.
Hình
18
Thật
ra, còn một chi tiết khác biệt nữa đó là id
attribute bên trong <h:inputText> tag. Tuy nhiên, ta
không cần khai báo attribute đặc biệt này. Việc duy nhất
nên làm là điều chỉnh lại giá trị id cho phù hợp
với ngữ cảnh mới. Ta đặt lại tên như sau
Hình
19
6.4.
Sử dụng composite component
Đến
đây ta đã sẵn sàng sử dụng inputScore composite
component để refactor index.xhtml, rồi thi hành
application để kiểm thử kết quả.
III.
Tổng kết
Bài
viết đã vận dụng một tính năng mạnh của JSF là
composite components để refactor một web page đang bị tình
trạng code duplication. Là software developer, ta không những
phải cung cấp những giải pháp hoạt động tốt, mà các
giải pháp đó còn phải có khả năng phát triển và bảo
trì về sau. Muốn được như vậy, code duplication là một
trong những vấn đề nghiêm trọng mà ta cần phải lưu ý
loại bỏ.
IV.
Tài liệu tham khảo
- Gaddis T. (2010) Starting Out with Java From Control Structures Through Objects, (4th edition), Pearson Education, Boston. Chương 3.
Nhận xét này đã bị quản trị viên blog xóa.
Trả lờiXóa