Bài tập lớn Nhập môn Công nghệ Phần mềm

Đề tài: Refactoring

Sinh viên : Lê Ngọc Minh
Lớp

: Khoa học máy tính

Khoá

: 52

SHSV

: 20071946

Giáo viên : Lê Đức Trung

Hà Nội, tháng 03/2011

Mục lục
Chương 1. Giới thiệu..........................................................................................................4
Chương 2. Các nguyên lý về refactoring............................................................................5
2.1. Định nghĩa refactoring............................................................................................5
2.2. Hai chiếc mũ............................................................................................................5
2.3. Tại sao cần refactor?...............................................................................................6
2.3.1. Refactoring giúp cải thiện thiết kế...................................................................6
2.3.2. Refactoring giúp phần mềm dễ hiểu hơn.........................................................6
2.3.3. Refactoring giúp bạn lập trình nhanh hơn........................................................6
2.4. Khi nào nên refactor?..............................................................................................7
2.4.1. Nguyên tắc 3 lần...............................................................................................7
2.4.2. Refactor khi thêm chức năng...........................................................................7
2.4.3. Refactor khi sửa lỗi..........................................................................................7
2.4.4. Refactor khi xem lại mã nguồn (code review).................................................7
2.5. Các vấn đề khi refactor............................................................................................7
2.5.1. Cơ sở dữ liệu....................................................................................................7
2.5.2. Thay đổi giao diện............................................................................................8
2.6. Refactoring với thiết kế...........................................................................................8
2.7. Refactoring với hiệu năng.......................................................................................9
Chương 3. Nhận biết mã nguồn cần refactor...................................................................10
3.1. Trùng lặp mã.........................................................................................................10
3.2. Phương thức dài....................................................................................................10
3.3. Lớp lớn..................................................................................................................11
Chương 4. Xây dựng bộ kiểm thử....................................................................................12
4.1. Giá trị của mã kiểm thử.........................................................................................12
Chương 5. Các phương pháp refactor..............................................................................13
5.1. Định dạng của các phương pháp refactor..............................................................13
5.2. Trích phương thức.................................................................................................13
5.2.1. Tóm tắt...........................................................................................................13
5.2.2. Động cơ..........................................................................................................14
5.2.3. Ví dụ: Không có biến nội bộ..........................................................................14
5.2.4. Ví dụ: Có sử dụng biến nội bộ.......................................................................15
5.2.5. Ví dụ: Gán lại một biến nội bộ.......................................................................16
5.3. Nhập phương thức (Inline method).......................................................................17
5.3.1. Tóm tắt...........................................................................................................17
5.3.2. Động cơ..........................................................................................................18
5.4. Nhập biến tạm.......................................................................................................18
5.4.1. Tóm tắt...........................................................................................................18
5.4.2. Động cơ..........................................................................................................19
5.5. Di chuyển phương thức.........................................................................................19
5.5.1. Tóm tắt...........................................................................................................19
5.5.2. Động cơ..........................................................................................................19

5.5.3. Ví dụ...............................................................................................................19
Chương 6. Các công cụ refactor.......................................................................................21
6.1. Refactor bằng công cụ...........................................................................................21
6.2. Refactor mã nguồn Java bằng Eclipse...................................................................21
6.2.1. Thực đơn refactor...........................................................................................21
6.2.2. Đổi tên............................................................................................................22
6.2.3. Trích phương thức..........................................................................................23
6.2.4. Nhập phương thức..........................................................................................23
6.2.5. Nhập biến tạm................................................................................................24
6.2.6. Di chuyển phương thức..................................................................................24
Phụ lục A. Tài liệu tham khảo..........................................................................................26
Phụ lục B. Danh sách “bad smells in code”.....................................................................27
Phụ lục C. Danh sách các phương pháp refactor..............................................................28
Phụ lục D. Các công cụ refactor mã nguồn Java trong Eclipse Helios............................31

Chương 1. Giới thiệu
Refactoring là quá trình thay đổi một hệ thống phần mềm nhằm cái tiến cấu trúc bên
trong nhưng không làm biến đổi hành vi bên ngoài của nó. Refactoring là việc dọn dẹp
mã nguồn một cách có tổ chức sao cho tối thiểu hoá khả năng gây ra lỗi. Về bản chất
refactoring là nâng cấp thiết kế của mã nguồn sau khi nó đã được viết ra.
Trong những hiểu biết thông thường về công nghệ phần mềm, chúng ta thiết kế trước
sau đó mới cài đặt. Cần có thiết kế tốt trước sau đó mới có cài đặt tốt. Qua thời gian, mã
nguồn bị sửa đổi và sự nhất quán của hệ thống, cấu trúc của nó theo thiết kế, dần dần mờ
nhạt. Quá trình cài đặt chuyển dần từ chế tạo sang chắp vá.
Refactoring là cách làm ngược lại. Khi refactor bạn có thể lấy một thiết kế tồi, thậm chí
là hỗn loạn, và làm lại để nó trở thành một mã nguồn được thiết kế tốt. Mỗi bước đều
đơn giản, thậm chí rất đơn giản. Bạn chỉ chuyển một trường từ lớp này sang lớp khác,
lấy vài đoạn mã ra khỏi phương thức để tạo ra phương thức riêng và đẩy vài đoạn mã lên
hay xuống cây thừa kế. Tuy nhiên tác động tích luỹ của những thay đổi nhỏ đó có thể cái
thiện đáng kể thiết kế. Đó là sự đảo ngược của khái niệm software decay.
Khi refactor bạn sẽ nhận thấy sự phân phối công việc thay đổi. Thiết kế thay vì diễn ra
đầu tiên, lại diễn ra liên tục trong suốt quá trình phát triển. Bạn học được cách cải tiến
thiết kế từ việc xây dựng hệ thống. Kết quả của sự tương tác này dẫn đến một chương
trình với thiết kế luôn tốt khi quá trình phát triển tiếp diễn.
Qua quá trình phát triển của công
nghệ phần mềm, cùng với sự phát
triển mạnh mẽ của phần cứng thì yêu
cầu về hiệu suất xử lý ngày càng ít
quan trọng thay vào đó, tính dễ hiểu
được đề cao. Do đó các kỹ thuật
refactoring cũng ngày càng được chú
ý nhằm nâng cao chất lượng phần
mềm.
Thực tế học tập của sinh viên Việt
Nam cho thấy các phần mềm được
viết trên ghế nhà trường thường không
có được thiết kế tốt ngay từ ban đầu. Dẫn đến tình trạng này có rất nhiều nguyên nhân
chủ quan lẫn khách quan như thiếu kinh nghiệm, thiếu thời gian, chưa chú trọng đến quy
trình phát triển phần mềm v.v... Để những phần mềm này vượt ra khỏi phạm vi của
những bài tập lớn, đồ án môn học, đồ án tốt nghiệp... tiếp tục phát triển thành sản phẩm
thực tế và thành công trong cuộc sống thì kỹ năng refactoring là rất cần thiết.

Chương 2. Các nguyên lý về refactoring
2.1.

Định nghĩa refactoring

Thuật ngữ refactoring được phát minh bởi Ward Cunningham và Kent Beck vào khoảng
những năm 1980 khi làm việc với ngôn ngữ Smalltalk. Trong cuốn sách “Refactoring:
Improving the Design of Existing Code” cung cấp hai định nghĩa như sau:
Refactoring (danh từ): một sự thay đổi ở cấu trúc bên trong của phần mềm giúp nó dễ
hiểu và dễ sửa đổi hơn mà không làm thay đổi hành vi bên ngoài.
Refactor (động từ): tái cấu trúc phần mềm bằng cách áp dụng một loạt thao tác
refactoring mà không làm thay đổi hành vi bên ngoài.
Trong một số tài liệu tiếng Việt, refactoring được chuyển ngữ thành “cải tiến mã nguồn”
tuy nhiên cách nói này khá dài dòng và cũng không diễn tả được hết ý nghĩa của thuật
ngữ. Tài liệu này sẽ để nguyên thuật ngữ tiếng Anh với hai dạng như trên, ngoài ra
refactoring cũng được hiểu là tổng hợp các phương pháp và công cụ để tiến hành
refactor phần mềm nói chung.
Như vậy, hiểu theo nghĩa nào đó refactor chỉ đơn giản là dọn dẹp mã nguồn. Tuy nhiên
bằng cách áp dụng những phương pháp, công cụ của refactoring, việc dọn dẹp mã nguồn
sẽ hiệu quả hơn đáng kể.
Cần phân biệt refactoring và tối ưu hoá hiệu năng (performance optimization). Mục đích
của refactoring là làm cho phần mềm dễ hiểu và dễ sửa chữa hơn. Tối ưu hoá hiệu năng
cũng không làm thay đổi hành vi bên ngoài của phần mềm (trừ tốc độ) mà chỉ thay đổi
cấu trúc bên trong tuy nhiên việc tối ưu hoá thường dẫn đến những đoạn mã nguồn khó
hiểu và khó sửa chữa.
Một đặc tính quan trọng nữa của refactoring là không thay đổi hành vi bên ngoài của
phần mềm. Phần mềm vẫn phải thực hiện những chức năng giống hệt những gì nó làm
trước đó. Người dùng, kể cả end user và lập trình viên, không thể nhận ra rằng có gì đó
vừa thay đổi.
2.2.

Hai chiếc mũ

Kent Beck sử dụng hình ảnh hai chiếc mũ để chỉ quá trình phát triển phần mềm có
refactor. Bạn chia thời gian ra thành hai hoạt động tách biệt: thêm chức năng và refactor.
Khi thêm chức năng, bạn không nên thay đổi những đoạn mã đã có, bạn chỉ thêm vào
những khả năng mới. Bạn có thể đo tiến độ bằng cách tạo ra các bộ test và đảm bảo nó
chạy. Khi refactor, bạn không thêm chức năng nào mà chỉ tái cấu trúc mã nguồn. Bạn
cũng không thêm bộ test nào (trừ khi phát hiện ra một bộ test bạn đã bỏ lỡ trước đó) và
chỉ thay đổi một bộ test khi thực sự cần thiết để phù hợp với sự thay đổi của giao diện.

2.3.
2.3.1.

Tại sao cần refactor?
Refactoring giúp cải thiện thiết kế

Không có refactoring, thiết kế của phần mềm sẽ phân rã (software decay). Khi mã
nguồn được thay đổi để hiện thực hoá những mục tiêu ngắn hạn hoặc thay đổi mà không
hiểu đầy đủ thiết kế, mã nguồn mất dần cấu trúc. Ngày càng khó nhận ra thiết kế bằng
cách đọc mã nguồn. Refactoring giống như sắp xếp lại mã nguồn. Bạn xếp lại những gì
không ở đúng chỗ của nó. Sự mất cấu trúc của mã nguồn có hiệu ứng tích luỹ. Càng khó
nhận ra thiết kế từ mã nguồn thì càng khó duy trì thiết kế đó. Refactoring thường xuyên
có thể giúp mã nguồn giữ được hình dạng.
Mã nguồn được thiết kế không tốt thường chữa nhiều đoạn mã làm cùng một việc, thông
thường là do mã nguồn hay làm cùng một việc ở những chỗ khác nhau. Vì thế một khía
cạnh quan trọng của cải tiến thiết kế là xoá bỏ những đoạn mã trùng lặp. Tầm quan trọng
của việc này nằm ở những thay đổi mã nguồn trong tương lai. Giảm lượng mã không
giúp hệ thống chạy nhanh hơn chút nào nhưng lại khiến việc sửa đổi dễ dàng hơn rất
nhiều. Có ít mã cần phải hiểu hơn và chỉ cần sửa ở một nơi sự thay đổi sẽ được áp dụng
trên toàn bộ hệ thống.
2.3.2.

Refactoring giúp phần mềm dễ hiểu hơn

Lập trình giống như cuộc trò chuyện với máy tính. Bạn viết mã để bảo máy tính cần phải
làm gì và nó sẽ trả lời bằng cách làm chính xác điều bạn bảo. Bạn cần xoá bỏ khoảng
cách giữa điều bạn muốn máy tính làm với điều bạn nói với nó. Lập trình theo cách hiểu
này chỉ đơn giản là nói chính xác điều bạn muốn. Tuy nhiên còn có những người khác
cần sử dụng mã nguồn của bạn. Ai đó sẽ thử đọc mã nguồn của bạn trong thời gian vài
tháng để có thể sửa đổi vài chỗ. Chúng ta dễ quên mất người sử dụng bổ sung đó, trong
khi họ thực ra lại là những người quan trọng nhất. Ai bận tâm nếu máy tính mất thêm vài
xung nhịp để dịch? Nhưng sự khác biệt sẽ rất lớn nếu một lập trình viên mất một tuần để
thực hiện một sự sửa đổi trong khi đáng lẽ mất vài giờ nếu anh ta hiểu mã nguồn của
bạn.
Bạn cũng có thể sử dụng refactoring như một cách để hiểu những đoạn mã của người
khác. Đọc một vài dòng mã và cố gắng thay đổi nó để phản ánh đúng hơn cách hiểu của
bạn sau đó thử chạy lại xem nó còn làm việc hay không. Với cách làm này dần dần bạn
sẽ có hiểu biết chắc chắn về hệ thống và việc trở lại những đoạn mã đã được refactoring
sẽ dễ dàng hơn nhiều.
2.3.3.

Refactoring giúp bạn lập trình nhanh hơn

Điều này nghe như một nghịch lý. Để nâng cao chất lượng mã nguồn, chúng ta cần đầu
tư thời gian vào việc refactoring, chẳng phải việc đó sẽ làm giảm năng suất?
Thực tế chứng minh rằng thiết kế tốt là rất quan trọng đối với tốc độ phát triển phần
mềm. Không có một thiết kế tốt, bạn có thể tiến nhanh một lúc nhưng sau đó sẽ sớm

chậm lại. Bạn phải dành thời gian tìm và sửa lỗi thay vì thêm chức năng mới. Việc sửa
đổi lâu hơn vì bạn phải cố hiểu hệ thống và tìm những đoạn mã trùng lặp.
Thiết kế tốt là điều kiện cần để duy trì tốc độ phát triển phần mềm và refactoring giúp
bạn chống lại sự phân rã (decay) của thiết kế, thậm chí còn cải thiện thiết kế nữa.
2.4.
2.4.1.

Khi nào nên refactor?
Nguyên tắc 3 lần

Lần đầu tiên bạn làm gì đó, hãy làm. Lần thứ hai bạn làm điều tương tự, bạn nhận ra sự
lặp lại nhưng vẫn làm. Lần thứ ba bạn làm điều tương tự, hãy refactor.
2.4.2.

Refactor khi thêm chức năng

Hoặc một phần đoạn mã cần viết đã được viết ở đâu đó hoặc bạn nhận thấy việc thay đổi
chút ít thiết kế có thể giúp cài đặt chức năng nhanh chóng hơn, hãy refactor. Đừng chỉ
bỏ qua những sai sót trong thiết kế, hãy refactor nó để công việc tiếp theo được thuận lợi
hơn.
2.4.3.

Refactor khi sửa lỗi

Lỗi được báo cáo là dấu hiệu cho thấy cần refactor. Refactoring giúp bạn hiểu rõ mã
nguồn hơn và tìm và loại bỏ lỗi dễ dàng hơn.
2.4.4.

Refactor khi xem lại mã nguồn (code review)

Xem lại mã nguồn giúp lan truyền kiến thức trong nhóm phát triển, tạo cơ hội cho các
lập trình viên cũ truyền kinh nghiệm cho những lập trình viên mới hơn. Refactor khiến
người review không chỉ tưởng tượng ra mã nguồn trông ra sao với những đề nghị của
mình mà thực sự nhìn thấy nó. Quá trình xem lại có kết quả rõ ràng hơn, không chỉ là
một vài đề nghị mà là những đề nghị đã được thực hiện.
2.5.
2.5.1.

Các vấn đề khi refactor
Cơ sở dữ liệu

Nhiều ứng dụng gắn chặt với lược đồ dữ liệu hỗ trợ nó, đây là một lý do khiến cơ sở dữ
liệu khó thay đổi. Một lý do khác là việc chuyển đổi dữ liệu có thể rất lâu và nguy hiểm.
Với các cơ sở dữ liệu phi đối tượng một cách giải quyết là đặt một tầng phần mềm giữa
mô hình đối tượng và mô hình cơ sở dữ liệu. Bằng cách đó bạn có thể tách rời các thay
đổi giữa hai mô hình. Bạn cũng không cần thiết phải tạo một lớp riêng biệt từ đầu. Bạn
có thể xây dựng lớp này khi nhận ra mô hình đối tượng không còn ổn định.
Cơ sở dữ liệu hướng đối tượng vừa hỗ trợ vừa cản trở. Một vài cơ sở dữ liệu hướng đối
tượng có khả năng chuyển đổi tự động từ phiên bản này sang phiên bản khác của đối

tượng. Nếu không, bạn phải rất cẩn thận khi chuyển đổi dữ liệu bằng tay. Bạn có thể
thoải mái di chuyển các hành vi nhưng với các trường thì phải cần thận. Có thể sử dụng
hàm truy cập để tạo ra cảm giác là dữ liệu đã được chuyển và khi chắc chắn về sự thay
đổi bạn có thể thực sự di chuyển trường.
2.5.2.

Thay đổi giao diện

Khi làm việc với đối tượng bạn có thể tuỳ ý thay đổi nội dung bên trong miễn là giao
diện vẫn giữ nguyên. Nếu cần thay đổi giao diện và bạn có thể thay đổi tất cả những nơi
sử dụng nó, bạn chỉ việc sửa tất cả đồng thời. Tuy nhiên nếu bạn có một giao diện đã
được công bố, mọi việc trở nên phức tạp hơn nhiều. Bạn không thể sửa những đoạn mã
do người khác viết sử dụng giao diện của bạn. Bạn cần một quy trình phức tạp hơn
nhiều.
Khi refactor một giao diện đã được công bố, bạn cần giữ lại toàn bộ giao diện cũ, ít nhất
cho đến khi người sử dụng có thể phản ứng với sự thay đổi. Nếu bạn đổi tên một hàm,
hãy giữ lại hàm cũ và cho nó gọi đến hàm mới. Đừng sao chép thân hàm vì bạn sẽ lại
mất thời gian xử lý sự trùng lặp mã nguồn. Bạn cũng nên sử dụng công cụ deprecate của
Java để thông báo những chỗ bị phản đối.
Công bố giao diện có ích lợi của nó nhưng cũng gây nhiều khó khăn vì vậy nếu có thể,
đừng công bố giao diện. Tất nhiên nếu bạn thiết kế thư viện lập trình, điều đó là không
tránh khỏi. Nhưng nếu bạn làm một phần mềm với nhóm làm việc gồm ba người, đừng
công bố giao diện từ người này đến người kia. Đơn giản là hãy mở mã nguồn ra và sửa
đổi.
2.6.

Refactoring với thiết kế

Một số người ví thiết kế với bản vẽ của kĩ sư và lập trình với công việc của thợ xây. Tuy
nhiên phần mềm khác với nhà cửa đường xá. Alistair Cockburn nói, “Khi thiết kế tôi có
thể nghĩ rất nhanh nhưng suy nghĩ của tôi đầy những lỗ hổng nhỏ.”
Một số khác tranh luận rằng refactoring là sự thay thế cho thiết kế. Trong cách tiếp cận
này bạn hoàn toàn không thiết kế chút nào. Bạn chỉ lập trình theo cách đầu tiên nghĩ ra,
làm cho nó chạy đúng và sau đó refactor. Thực tế cách làm này có thể thực hiện được
nhưng không phải cách hiệu quả nhất.
Khi áp dụng refactoring, bạn không đặt áp lực lên thiết kế ban đầu. Bạn không tìm kiếm
giải pháp tốt nhất mà chấp nhận một giải pháp hợp lý. Cùng với quá trình phát triển và
hiểu rõ hơn bài toán bạn phát hiện ra những giải pháp hợp lý hơn mà đưa nó vào hệ
thống.
Một kết quả quan trọng của refactoring là sự đơn giản trong thiết kế. Với cách thiết kế
hoàn chỉnh từ đầu, bạn cần tìm ra giải pháp thật mềm dẻo để đáp ứng sự thay đổi của
yêu cầu. Vấn đề là thiết kế mềm dẻo thì phức tạp và tốn kém hơn thiết kế đơn giản. Khi
tiếp cận vấn đề với refactoring, bạn sẽ tự hỏi “Để refactor thiết kế đơn giản này thành
thiết kế mềm dẻo có khó không?” Nếu câu trả lời là “khá dễ”, bạn chỉ việc cài đặt giải

pháp đơn giản.
Như vậy refactoring dẫn đến những thiết kế đơn giản hơn mà không phải hy sinh sự
mềm dẻo. Khi bạn đã có một nhận thức nhất định về những gì có thể refactor dễ dàng,
bạn thậm chí không nghĩ đến thiết kế mềm dẻo nữa. Chỉ việc xây dựng những gì đơn
giản nhất làm việc được. Hầu hết thời gian bạn sẽ không cần dùng đến những thiết kế
mềm dẻo và phức tạp nữa.
2.7.

Refactoring với hiệu năng

Mối quan ngại phổ biến với refactoring là làm giảm hiệu năng của chương trình. Trong
hầu hết trường hợp refactoring thực sự làm chương trình chậm đi. Tuy nhiên bí mật của
những chương trình chạy nhanh, trừ những trường hợp cực kì nghiêm ngặt, là trước tiên
nó được làm để dễ dàng tinh chỉnh, sau đó mới được tinh chỉnh để đạt tốc độ mong
muốn.
Một điều thú vị về hiệu năng là các chương trình thường tốn nhiều thời gian nhất vào
một phần nhỏ của mã nguồn. Do vậy nếu bạn tối ưu hoá toàn bộ mã nguồn như nhau thì
bạn sẽ lãng phí 90% công sức vào việc tối ưu hoá những đoạn mã không được chạy
nhiều.
Áp dụng nhận xét này bạn sẽ viết những chương trình tốt mà không để ý nhiều đến hiệu
năng. Đến khi bắt đầu bước tối ưu hoá, thường khá muộn trong quá trình phát triển, bạn
bắt đầu sử dụng chương trình profiler để phân tích những đoạn mã tốn thời gian và bộ
nhớ nhiều nhất. Tập trung vào những điểm nóng này, bạn sửa đổi mã nguồn và kiểm tra
sự tiến bộ về hiệu năng cho đến khi đạt được mục tiêu.
Refactoring giúp sự tối ưu hoá dễ dàng hơn theo hai cách. Thứ nhất, vì cài đặt nhanh
hơn, bạn có nhiều thời gian hơn để tối ưu hoá. Thứ hai, mã nguồn được chia nhỏ hơn để
dễ dàng phát hiện những điểm nóng và dễ hiểu hơn để bạn tối ưu hoá dễ dàng.

Chương 3. Nhận biết mã nguồn cần refactor
Hiểu thế nào là refactoring không có nghĩa là bạn đã biết nên refactor lúc nào và ở đâu.
Mục đích của chương này là đưa ra những chỉ dẫn để bạn nhận biết những vấn đề trong
mã nguồn và biết cách khắc phục. Các tác giả Martin Fowler và Kent Beck gọi chúng là
“bad smells in code” (tạm dịch: mùi hôi trong mã nguồn).
Đây không phải là những thước đo chuẩn để nói rõ đoạn mã nào có vấn đề và đoạn mã
nào không, những thước đo như thế thậm chí có thể không tồn tại. Tuy nhiên bạn sẽ xây
dựng được cho mình những cảm nhận riêng rằng bao nhiêu biến là quá nhiều, phương
thức bao nhiêu dòng là quá dài...
Danh sách các “bad smells” được đề xuất bởi Martin Fowler và Kent Beck tương đối
dài, ở đây xin giới thiệu một số vấn đề thường gặp. Hãy tham khảo Phụ lục B để xem
danh sách đầy đủ.
3.1.

Trùng lặp mã

Đứng đầu trong những “mùi hôi” là mã nguồn trùng lặp. Nếu bạn thấy cùng một cấu
trúc xuất hiện ở nhiều nơi, bạn có thể chắc chắn rằng sẽ tốt hơn nếu bạn hợp nhất chúng
lại.
Đơn giản nhất là trường hợp cùng một biểu thức xuất hiện trong hai phương thức của
cùng một lớp. Khi đó bạn chỉ việc Trích phương thức và gọi nó từ cả hai nơi.
Một vấn đề thường gặp khác là khi cùng một biểu thức được sử dụng ở hai lớp chị em.
Bạn có thể xoá bỏ sự trùng lặp này bằng cách Trích phương thức ở cả hai lớp rồi sau đó
Kéo lên. Nếu đoạn mã tương tự nhưng không giống hệt nhau, bạn cần Trích phương
thức để tách đoạn giống và đoạn khác nhau. Sau đó bạn có thể Tổ chức phương thức
mẫu. Nếu các phương thức làm cùng một việc với những giải thuật khác nhau, bạn có
thể chọn giải thuật rõ ràng hơn và sử dụng Thay thế giải thuật.
Nếu bạn có những đoạn mã trùng lặp trong các lớp không liên quan, hãy xem xét đến
việc sử dụng Trích lớp từ một lớp và sử dụng thành phần mới ở lớp còn lại. Một khả
năng khác là phương thức đáng lẽ chỉ thuộc về một lớp và được gọi bởi lớp còn lại hoặc
phương thức thuộc về một lớp thứ ba và được sử dụng bởi cả hai lớp. Bạn cần quyết
định xem phương thức có nghĩa ở đâu và đảm bảo rằng nó phải ở đó mà không phải nơi
nào khác.
3.2.

Phương thức dài

Chương trình hướng đối tượng tốt nhất và sống lâu nhất là chương trình có các phương
thức ngắn. Mọi người đều nhận ra rằng phương thức càng dài thì càng khó hiểu. Các
phương thức ngắn với tên gọi được đặt hợp lý có thể tiết kiệm rất nhiều thời gian vì bạn
không cần đọc thân hàm.
Trong 99% trường hợp, tất cả những gì cần làm để rút ngắn phương thức là Trích
phương thức. Hãy tìm những phần của phương thức kết hợp được với nhau và tạo ra

phương thức mới.
Nếu bạn có một phương thức với rất nhiều tham số và biến tạm, những thành phần này
có thể cản trở việc trích phương thức. Bạn sẽ phải truyền quá nhiều tham số và biến tạm
như là tham số cho những phương thức được trích ra và kết quả còn khó đọc hơn cả lúc
đầu. Bạn có thể sử dụng Thay biến tạm bởi truy vấn để loại bỏ một số biến tạm. Danh
sách tham số dài có thể được trở thành gọn gàng với các phương pháp Tạo đối tượng
tham số và Giữ đối tượng nguyên vẹn.
Nếu bạn đã thực hiện những cách trên mà vẫn có quá nhiều biến tạm và tham số, đã đến
lúc dùng đến pháo hạng nặng: Thay phương thức bằng đối tượng phương thức.
Làm thế nào để xác định những đoạn mã có thể trích ra? Cách khá tốt là tìm chú thích.
Một đoạn mã với chú thích chỉ ra rằng nó có thể được thay bởi một phương thức có tên
dựa trên nội dung chú thích. Thậm chí một dòng cũng đáng để trích nếu nó cần phải
được giải thích.
Các câu lệnh điều kiện và vòng lặp cũng là dấu hiệu cần trích phương thức. Sử dụng
Phân ly điều kiện để xử lý các biểu thức điều kiện. Với vòng lặp, trích nó và mã nguồn
bên trong thành một phương thức riêng.
3.3.

Lớp lớn

Khi một lớp làm quá nhiều việc, nó thường thể hiện ở chỗ có quá nhiều biến thể hiện
(instance variables). Khi một lớp có quá nhiều biến thể hiện, trùng lặp mã nguồn chắc
chắn không xa.
Bạn có thể Trích lớp để nhóm một số biến. Chọn những biến có thể chung sống với nhau
trong một thành phần. Chẳng hạn “depositAmount” và “depositCurrency” có nhiều khả
năng cùng thuộc về một thành phần. Nói chung, chia sẻ một tiền tố hoặc hậu tố trong
một tập con của các biến trong một lớp gợi ý cần một thành phần mới. Nếu thành phần
này thích hợp làm lớp con, bạn sẽ thấy Trích lớp con dễ thực hiện hơn.
Đôi khi một lớp không sử dụng tất cả các biến thể hiện của nó trong tất cả thời gian. Nếu
thế, bạn có thể áp dụng Trích lớp và Trích lớp con nhiều lần.
Cũng như lớp có quá nhiều biến, một lớp có quá nhiều mã là mảnh đất màu mỡ cho sự
trung lặp mã nguồn, hỗn loạn và sự thất bại. Giải pháp đơn giản nhất là giảm sự dư thừa
trong bản thân lớp. Nếu bạn có những phương thức dài 500 dòng mã với rất nhiều phần
chung, bạn có thể biến nó thành năm phương thức mười dòng với mười phương thức hai
dòng trích từ phương thức ban đầu.
Giải pháp thường gặp cho trường hợp này là Trích lớp và Trích lớp con. Một mẹo hữu
ích là sử dụng Trích giao diện để xác định khách hàng sử dụng lớp như thế nào. Cách
này có thể cho bạn một vài ý tưởng về cách chia nhỏ thêm lớp.
Nếu lớp lớn của bạn lại là một lớp GUI, bạn có thể phải chuyển dữ liệu và hành vi sang
một đối tượng nghiệp vụ khác. Điều này có thể cần phải nhân bản dữ liệu chuyển cả hai
nơi và giữ dữ liệu đồng bộ. Nhân bản dữ liệu gọi ý cách thực hiện việc này.

Chương 4. Xây dựng bộ kiểm thử
Nếu bạn muốn refactor, điều kiện tiên quyết là phải có bộ kiểm thử chắc chắn. Ngay cả
khi bạn có những công cụ có thể tự động hoá refactoring, bạn vẫn cần kiểm thử. Sẽ còn
rất lâu nữa trước khi mọi thao tác refactor đều có thể thực hiện bằng công cụ.
4.1.

Giá trị của mã kiểm thử

Nếu bạn quan sát hầu hết các lập trình viên sử dụng thời gian của họ, bạn sẽ nhận ra
rằng viết mã thực ra chỉ chiếm một phần nhỏ. Một ít thời gian để tìm hiểu cần phải làm
gì để viết tiếp, một ít để thiết kế, nhưng hầu hết thời gian được dùng để gỡ lỗi. Chắc
chắn bạn sẽ nhớ những tiếng đồng hồ dài gỡ lỗi, nhiều khi giữa đêm khuya. Mọi lập
trình viên đều có thể kể chuyện một lỗi khiến anh ta mất cả ngày (hoặc nhiều hơn) để
tìm ra. Sửa lỗi thường thường khá nhanh, nhưng tìm ra nó là cả một cơn ác mộng. Và
khi bạn sửa một lỗi, luôn luôn có khả năng một lỗi khác sẽ xuất hiện mà bạn không biết
cho đến rất lâu sau. Bạn sẽ mất nhiều năm để tìm ra lỗi đó.
Mã nguồn tự kiểm tra (self-testing code) là cách để máy tính tự động kiểm tra lỗi giúp
bạn. Các công cụ hiện nay cho phép bạn viết những đoạn mã khi được chạy sẽ đưa ra
thông báo lỗi nếu những kỳ vọng không được thoả mãn. Ngay khi viết một hàm nào đó,
hãy viết ngay mã kiểm tra sự thực hiện của hàm đó. Bạn chỉ phải viết mã này một lần,
mỗi khi refactor hay bất cứ thay đổi nào khác với mã nguồn, bạn có thể chạy lại nó để
đảm bảo mọi thứ vẫn hoạt động chính xác.
Theo Martin Fowler, “một bộ kiểm thử là chiếc máy phát hiện lỗi mạnh mẽ loại bỏ thời
gian tốn để tìm lỗi.” Trên thực tế, dành thời gian để viết mã kiểm thử là một cách tiết
kiệm thời gian và phát triển phần mềm nhanh hơn.
Thậm chí một số phương pháp phát triển phần mềm hiện đại yêu cầu viết mã kiểm thử
trước khi viết chương trình. Bằng việc viết ra các trường hợp có thể xảy ra, bạn hiểu rõ
mình mong muốn điều gì ở tính năng sắp cài đặt. Viết test cũng giúp bạn tập trung vào
giao diện hơn là cài đặt (luôn luôn là thói quen tốt). Nó cũng có nghĩa bạn biết chắc khi
nào hoàn thành việc viết mã: khi test chạy được.
Định nghĩa refactoring yêu cầu quá trình này không làm thay đổi hành vi bên ngoài của
hệ thống. Sử dụng mã kiểm thử là một cách rõ ràng để đạt được mục đích này. Mỗi khi
bạn thực hiện một thao tác refactoring, hãy nhớ chạy lại toàn bộ test để đảm báo nó
không gây ra lỗi trước khi thực hiện thao tác tiếp theo.

Chương 5. Các phương pháp refactor
Martin Fowler trong cuốn sách của ông dẫn ra một danh sách dài các phương thức khác
nhau để refactor. Trong giới hạn của tài liệu này tôi không có điều kiện trình bày hết tất
cả mà chỉ chọn ra vài “gương mặt” tiêu biểu. Danh sách đầy đủ các phương pháp
refactor có ở Phụ lục C.
5.1.

Định dạng của các phương pháp refactor

Trong các phần tiếp theo, các phương pháp refactor được trình bày với một định dạng
thống nhất như sau:
• Bắt đầu bằng tên của phương pháp
• Sau đó là tóm tắt về tình huống bạn cần sử dụng phương pháp và nội dung
phương pháp.
• Phần động cơ mô tả tại sao phương pháp nên được thực hiện và những trường
hợp không nên dùng.
• Phần cơ chế trong sách được lược bỏ do các công cụ hiện tại đã hỗ trợ rất tốt
những thao tác refactor thường dùng.
• Các ví dụ cho một trường hợp rất đơn giản mà phương pháp được sử dụng để
minh hoạ cách nó làm việc.
5.2.

Trích phương thức

5.2.1.

Tóm tắt

Một đoạn mã nào đó có thể được nhóm lại.
Chuyển đoạn mã thành một phương thức, đặt tên để giải thích mục đích của phương
thức đó.
void printOwing(double amount) {
printBanner();
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + amount);
}
Chuyển thành:
void printOwing(double amount) {
printBanner();
printDetails(amount);

}
void printDetails (double amount) {
System.out.println ("name:" + _name);
System.out.println ("amount" + amount);
}
5.2.2.

Động cơ

Trích phương thức từ những phương thức dài hoặc những đoạn mã cần được chú thích là
một cách để hiểu mã tốt hơn.
Phương thức ngắn và được đặt tên tốt có nhiều ích lợi. Trước hết, nó tăng cơ hội được
các phương thức khác sử dụng khi các phương thức được tinh chỉnh. Thứ hai, nó giúp
các phương thức cấp cao hơn trông giống như một dãy các chú thích. Việc override cũng
dễ dàng hơn.
Đôi khi mọi người băn khoăn một phương thức nên dài bao nhiêu. Độ dài của phương
thức thực ra không phải vấn đề, điều quan trọng là khoảng cách về ngữ nghĩa giữa tên
phương thức và thân phương thức. Nếu việc trích rút cải thiện tính rõ ràng, hãy làm điều
đó, kể cả khi tên phương thức còn dài hơn đoạn mã bạn vừa trích.
5.2.3.

Ví dụ: Không có biến nội bộ

void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
// print banner
System.out.println ("**************************");
System.out.println ("***** Customer Owes ******");
System.out.println ("**************************");
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + outstanding);

}
Ta trích ra đoạn mã in banner:
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + outstanding);
}
void printBanner() {
// print banner
System.out.println ("**************************");
System.out.println ("***** Customer Owes ******");
System.out.println ("**************************");
}
5.2.4.

Ví dụ: Có sử dụng biến nội bộ

Với sự tồn tại của biến nội bộ: các tham số truyền vào hoặc biến tạm được định nghĩa
trong thân phương thức, ta có vấn đề cần giải quyết. Bạn cần phải xử lý các biến này
hoặc chấp nhận không thể refactor được.
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {

Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + outstanding);
}
Chuyển thành:
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
printDetails(outstanding);
}
void printDetails (double outstanding) {
System.out.println ("name:" + _name);
System.out.println ("amount" + outstanding);
}
5.2.5.

Ví dụ: Gán lại một biến nội bộ

Trong trường hợp này tình hình trở nên phức tạp hơn. Ta sẽ chỉ đề cập đến biến tạm.
Nếu có một phép gán vào tham số, bạn nên ngay lập tức áp dụng phương pháp Xoá phép
gán vào tham số.
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();

// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
printDetails(outstanding);
}
Sau khi trích:
void printOwing() {
printBanner();
double outstanding = getOutstanding();
printDetails(outstanding);
}
double getOutstanding() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
return outstanding;
}
5.3.

Nhập phương thức (Inline method)

5.3.1.

Tóm tắt

Thân một hàm cũng rõ ràng như tên của nó.
Đặt trực tiếp thân phương thức vào nơi gọi nó và xoá nó đi.
int getRating() {
return (moreThanFiveLateDeliveries()) ? 2 : 1;
}
boolean moreThanFiveLateDeliveries() {

return _numberOfLateDeliveries > 5;
}
Được refactor thành:
int getRating() {
return (_numberOfLateDeliveries > 5) ? 2 : 1;
}
5.3.2.

Động cơ

Một nguyên tắc lập trình là sử dụng những phương thức ngắn được đặt tên sao cho thể
hiện được mục đích của nó vì những phương thức như thế giúp mã nguồn rõ ràng và dễ
đọc hơn. Nhưng đôi khi bạn bắt gặp những phương thức mà thân của nó cũng rõ ràng
như cái tên của nó. Hoặc bạn refactor một đoạn mã thành một phương thức cũng rõ ràng
như tên của nó. Khi điều này xảy ra, bạn nên loại bỏ những phương thức đó. Chỉ dẫn có
thể có ích, nhưng chỉ dẫn không cần thiết chỉ gây bực mình.
Trường hợp khác mà Nhập phương thức nên được áp dụng là khi bạn có một nhóm các
phương thức bị phân chia không phù hợp. Bạn có thể nhập chúng lại thành một phương
thức lớn sau đó trích lại thành các phương thức khác. Bạn nên làm động tác này trước
khi áp dụng Thay phương thức bằng đối tượng phương thức. Bạn nhập các lời gọi từ
phương thức có hành động bạn mong muốn trong đối tượng phương thức. Di chuyển
một phương thức sẽ dễ dàng hơn phương thức và những phương thức nó sử dụng.
Đôi khi người ta sử dụng quá nhiều chỉ dẫn và dường như các phương thức chỉ đơn giản
uỷ quyền cho phương thức khác. Trong những trường hợp đó, một số chỉ dẫn là đáng giá
nhưng không phải tất cả. Bằng cách Nhập phương thức, ta có thể giữ lại những phương
thức hữu ích và loại bỏ những gì còn lại.
5.4.
5.4.1.

Nhập biến tạm
Tóm tắt

Bạn có một biến tạm được gán một lần với một biểu thức đơn giản và nó gây cản trở các
refactoring khác.
Thay thể tất cả tham chiếu đến biến tạm đó bằng một biểu thức.
double basePrice = anOrder.basePrice();
return (basePrice > 1000)
Trở thành:
return (anOrder.basePrice() > 1000)

5.4.2.

Động cơ

Trong phần lớn trường hợp Nhập biến tạm được sử dụng như một phần của Thay biến
tạm bằng truy vấn, đó là động cơ chính. Trường hợp duy nhất Nhập biến tạm được sử
dụng một mình là khi bạn thấy một biến tạm được gán giá trị trả về của một phương
thức. Thường thường biến này không gây hại và bạn có thể mặc kệ nó một cách an toàn.
Nếu biến này gây cả trở các phương pháp refactoring, ví dụ như Trích phương thức, đến
lúc cần nhập nó.
5.5.

Di chuyển phương thức

5.5.1.

Tóm tắt

Một phương thức được sử dụng bởi một lớp khác nhiều hơn là lớp mà nó được định
nghĩa.
Tạo một phương thức mới với thân tương tự trong lớp sử dụng nó nhiều nhất. Hoặc
chuyển phương thức cũ thành những sự uỷ quyền hoặc xoá hẳn nó đi.
5.5.2.

Động cơ

Di chuyển phương thức là phần không thể tách rời của refactoring. Thường khi lớp có
quá nhiều hành vi hay các lớp tương tác quá nhiều, chúng bị gắn với nhau (coupled).
Bằng cách di chuyển vài phương thức, bạn có thể làm cho các lớp đơn giản hơn và hợp
lý hơn.
Sau khi bạn di chuyển một trường nào đó, hãy nhìn qua các phương thức trong lớp để
tìm ra những phương thức truy cập đối tượng khác nhiều hơn chính đối tượng mà nó
được đặt. Khi bạn tìm thấy một phương thức cần di chuyển, bạn hãy nhìn vào các
phương thức gọi nó, các phương thức nó gọi đến và các phương thức nạp chồng trong
cây thừa kế. Đánh giá có nên tiếp tục dựa trên đối tượng mà phương thức có nhiều tương
tác hơn.
5.5.3.

Ví dụ

Một lớp biểu diễn tài khoản minh hoạ cho kỹ thuật này:
class Account...
double overdraftCharge() {
if (_type.isPremium()) {
double result = 10;
if (_daysOverdrawn > 7) result += (_daysOverdrawn - 7) * 0.85;
return result;
}

else return _daysOverdrawn * 1.75;
}
double bankCharge() {
double result = 4.5;
if (_daysOverdrawn > 0) result += overdraftCharge();
return result;
}
private AccountType _type;
private int _daysOverdrawn;
Giả sử bạn có một vài loại tài khoản, mỗi loại có quy tắc riêng để tính tiền thấu chi
(overdraft charge). Nên di chuyển hàm overdraftCharge() đến các loại tài khoản đó.

Chương 6. Các công cụ refactor
6.1.

Refactor bằng công cụ

Refactor sử dụng công cụ hiệu quả hơn nhiều so với refactor bằng tay. Ngay cả khi bạn
có bảo hiểm bằng bộ kiểm thử, refactor bằng tay vẫn tốn thời gian hơn rất nhiều.
Với sự hỗ trợ ngày càng cao của các công cụ, refactoring ngày càng ít tách rời khỏi lập
trình. Chúng ta sẽ không nói “bây giờ tôi đang lập trình” và “bây giờ tôi đang refactor”
nữa mà chỉ nói “Trích phần này của phương thức, đẩy nó lên lớp cha sau đó gọi phương
thức mới vừa tạo trong lớp con mà tôi đang làm việc”. Vì bạn không kiểm thử sau các
thao tác refactor tự động hoá nên việc chuyển đổi giữa hai chiếc mũ trở nên ít rõ ràng
hơn nhiều.
6.2.

Refactor mã nguồn Java bằng Eclipse

Ngày nay các công cụ refactor cho các ngôn ngữ định kiểu tĩnh đã rất đầy đủ. Để bạn
nắm được refactor áp dụng trong thực tế như thế nào, tôi sẽ sử dụng Eclipse với ngôn
ngữ Java để minh hoạ. Dưới đây trình bày một số công cụ thường dùng, danh sách đầy
đủ các công cụ được hỗ trợ bởi Eclipse Helios được cho trong Phụ lục D.
6.2.1.

Thực đơn refactor

Tại vị trí đang soạn thảo, nhấn phải chuột và chọn refactor hoặc sử dụng tổ hợp phím
Alt-Shift-T, bạn sẽ nhận được một thực đơn những thao tác refactor khả dĩ. Danh sách
này tuỳ thuộc vào nơi bạn đặt con trỏ nên nó có thể không cho thấy hết những khả năng
của Eclipse.
6.2.2.

Đổi tên

Đây là thao tác hay dùng nhất. Khi đặt con trỏ ở tên một lớp, biến hay phương thức và
nhấn tổ hợp phím Alt-Shift-R, tên được chọn sẽ được đánh dấu ở tất cả những nơi nó
xuất hiện trong cửa số soạn thảo hiện thời. Khi đó bạn hãy nhập tên mới bạn mong
muốn và nhấn enter. Tất cả những tham chiếu đến đối tượng đó cả trong và ngoài cửa sổ
hiện thời đều được đổi theo.

Bạn cũng có thể chọn một tệp mã nguồn Java và nhấn tổ hợp phím Alt-Shift-R hoặc
nhấn phím F2 để đổi tên lớp bên trong và cùng tên với tệp đó.

6.2.3.

Trích phương thức

Lựa chọn một đoạn mã và nhấn tổ hợp phím Alt-Shift-M hoặc kích hoạt thực đơn
refactor và chọn mục Extract method.
Trong hộp hội thoại, hãy điền tên phương thức mới, bạn có thể sắp xếp thứ tự các tham
số cũng như thay đổi tên, kiểu của tham số.

6.2.4.

Nhập phương thức

Trong khi con trỏ đang đặt ở tên một phương thức, sử dụng tổ hợp phím Alt-Shift-I hoặc
kích hoạt thực đơn refactor và chọn Inline.

6.2.5.

Nhập biến tạm

Trong khi con trỏ đặt ở tên một biến, nhấn tổ hợp phím Alt-Shift-I hoặc kích hoạt thực
đơn refactor > Inline...

6.2.6.

Di chuyển phương thức

Trong khi con trỏ đặt ở tên mộ phương thức, nhấn tổ hợp phím Alt-Shift-V hoặc kích
hoạt thực đơn refactor, chọn Move...

Phụ lục A. Tài liệu tham khảo
[1] Martin Fowler et al., Refactoring: Improving the Design of Existing Code, First
Edition, 1999
[2] Bộ môn Công nghệ Phần mềm Đại học Bách Khoa Hà Nội, Slide bài giảng Nhập
môn Công nghệ Phần mềm, 2001
[3] Wikipedia contributors, "Code refactoring," Wikipedia, The Free Encyclopedia,
http://en.wikipedia.org/w/index.php?title=Code_refactoring&oldid=419442858
(accessed March 21, 2011).
[4] Những người đóng góp vào Wikipedia, “Cải tiến mã nguồn,” Wikipedia, Bách
khoa toàn thư mở, http://vi.wikipedia.org/w/index.php?title=C%E1%BA%A3i_ti
%E1%BA%BFn_m%C3%A3_ngu%E1%BB%93n&oldid=4218952 (truy nhập
ngày 21 tháng 3 năm 2011).

Phụ lục B. Danh sách “bad smells in code”
1.

Mã nguồn trùng lặp

2.

Phương thức dài

3.

Lớp lớn

4.

Danh sách tham số dài

5.

Thay đổi bất đồng

6.

Shotgun surgery

7.

Feature envy

8.

Data clumps

9.

Ám ảnh dữ liệu nguyên thuỷ

10.

Câu lệnh switch

11.

Phân cấp thừa kế song song

12.

Lớp lười biếng

13.

Sự tổng quát để dành

14.

Trường tạm

15.

Chuỗi thông điệp

16.

Trung gian

17.

Thân mật không đúng cách

18.

Lớp thay thế với giao diện khác nhau

19.

Lớp thư viện không đầy đủ

20.

Lớp dữ liệu

21.

Của thừa kế bị từ chối

22.

Chú thích

Phụ lục C. Danh sách các phương pháp refactor
1.

Soạn thảo phương thức

1.1.

Trích phương thức

1.2.

Nhập phương thức

1.3.

Nhập biến tạm

1.4.

Thay biến tạm bằng truy vấn

1.5.

Tạo biến giải thích

1.6.

Tách biến tạm

1.7.

Bỏ các phép gán tham số

1.8.

Thay phương thức bằng đối tượng phương thức

1.9.

Thay thế giải thuật

2.

Di chuyển tính năng giữa các đối tượng

2.1.

Di chuyển phương thức

2.2.

Di chuyển trường

2.3.

Trích lớp

2.4.

Bỏ lớp

2.5.

Giấu delegate

2.6.

Xoá lớp trung gian

2.7.

Tạo phương thức ngoài

2.8.

Tạo phần mở rộng nội bộ

3.

Tổ chức dữ liệu

3.1.

Đóng gói trường nội bộ

3.2.

Thay giá trị bằng đối tượng

3.3.

Đổi giá trị thành tham chiếu

3.4.

Đổi tham chiếu thành giá trị

3.5.

Thay mảng bằng đối tượng

3.6.

Nhân bản dữ liệu

3.7.

Đổi liên kết một chiều thành liên kết hai chiều

3.8.

Đổi liên kết hai chiều thành liên kết một chiều

3.9.

Thay giá trị đặc biệt bằng hằng đặt tên

3.10.

Đóng gói trường

3.11.

Đóng gói tập hợp

3.12.

Thay thế bản ghi bằng lớp dữ liệu

3.13.

Thay thế mã kiểu bằng lớp

3.14.

Thay thế mã kiểu bằng lớp con

3.15.

Thay thế mã kiểu bằng trạng thái, chiến lược

3.16.

Thay thế lớp con bằng trường

4.

Đơn giản hoá biểu thức điều kiện

4.1.

Phân ly điều kiện

4.2.

Kết hợp biểu thức điều kiện

4.3.

Kết hợp đoạn mã điều kiện

4.4.

Xoá cờ điều khiển

4.5.

Thay thế điều kiện lồng bằng biểu thức canh

4.6.

Thay thế điều kiện bằng đa hình

4.7.

Tạo đối tượng null

4.8.

Tạo sự xác nhận (assertion)

5.

Khiến lời gọi hàm đơn giản hơn

5.1.

Đổi tên phương thức

5.2.

Thêm tham số

5.3.

Xoá tham số

5.4.

Tách truy vấn khỏi thay đổi

5.5.

Tham số hoá phương thức

5.6.

Thay tham số bằng phương thức tường minh

5.7.

Giữ đối tượng nguyên vẹn

5.8.

Thay tham số bằng phương thức

5.9.

Tạo đối tượng tham số

5.10.

Xoá phương thức thiết lập

5.11.

Giấu phương thức

5.12.

Thay hàm tạo bằng factory method

5.13.

Đóng gói sự ép kiểu xuống

5.14.

Thay mã lỗi bằng ngoại lệ

5.15.

Thay ngoại lệ bằng kiểm tra

6.

Đương đầu với sự tổng quát hoá

6.1.

Kéo lên trường

6.2.

Kéo lên phương thức

6.3.

Kéo lên thân hàm tạo

6.4.

Đẩy xuống phương thức

6.5.

Đẩy xuống trường

6.6.

Trích lớp con

6.7.

Trích lớp cha

6.8.

Trích giao diện

6.9.

Thu gọn cây kế thừa

6.10.

Tổ chức phương thức mẫu

6.11.

Thay kế thừa bằng uỷ quyền

6.12.

Thay uỷ quyền bằng kế thừa

7.

Refactoring lớn

7.1.

Tách đôi cây thừa kế

7.2.

Chuyển đổi thiết kế thủ tục thành đối tượng

7.3.

Tách nghiệp vụ khỏi trình bày

7.4.

Trích cây thừa kế

Phụ lục D. Các công cụ refactor mã nguồn Java trong Eclipse Helios
1.

Rename (Đổi tên)

2.

Move (Di chuyển)

3.

Change method signature (Đổi chữ kí của phương thức)

4.

Extract Method (Trích phương thức)

5.

Extract Local Variable (Trích biến cục bộ)

6.

Extract Constant (Trích hằng)

7.

Inline (Nhập phương thức, biến)

8.

Convert Anonymous Class to Nested (Chuyển lớp vô danh sang lớp lồng)

9.

Move Type to New File (Di chuyển kiểu sang tệp mới)

10.

Convert Local Variable to Field (Chuyển biến nội bộ thành trường)

11.

Extract Superclass (Trích lớp cha)

12.

Extract Interface (Trích giao diện)

13.

Use Supertype Where Possible (Sử dụng lớp cha, giao diện khi có thể)

14.

Push Down (Đẩy xuống)

15.

Pull Up (Kéo lên)

16.

Extract Class (Trích lớp)

17.

Introduce Parameter Object (Tạo đối tượng tham số)

18.

Introduce Indirection

19.

Introduce Factory

20.

Introduce Parameter (Tạo tham số)

21.

Encapsulate Field (Bao đóng trường)

22.

Generalize Declared Type (Tổng quát hoá)

23.

Infer Generic Type Arguments

Sign up to vote on this title
UsefulNot useful