Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 46 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
46
Dung lượng
313,96 KB
Nội dung
Tái cấu trúc cho mọi người Làm thế nào và tại sao lại sử dụng các tính năng tái cấu trúc được tự động hóa của Eclipse David Gallardo, Tư vấn phần mềm Tóm tắt: Eclipse cung cấp tập các phép tái cấu trúc (refactoring) tự động mạnh mẽ, so với những thứ khác, cho phép bạn đổi tên các phần tử Java™, di chuyển các lớp và các gói, tạo các giao diện từ các lớp cụ thể, chuyển các lớp lồng nhau vào các lớp mức cao nhất và lấy ra một phương thức mới từ các đoạn mã trong một phương thức cũ. Việc trở nên quen thuộc với các công cụ tái cấu trúc của Eclipse là một cách hay để cải thiện năng suất của bạn. Tổng quan về tính năng tái cấu trúc của Eclipse này, kèm với các ví dụ, giải thích cách thức và lí do sử dụng từng tính năng. Lí do cần tái cấu trúc? Tái cấu trúc (Refactoring) là thay đổi cấu trúc của một chương trình mà không làm thay đổi chức năng của nó. Tái cấu trúc là một kỹ thuật mạnh, nhưng nó cần được thực hiện cẩn thận. Mối nguy hiểm chính là các lỗi vô ý có thể được đưa vào, đặc biệt là khi tái cấu trúc được thực hiện bằng tay. Mối nguy hiểm này dẫn đến một sự chỉ trích thường xuyên về tái cấu trúc: tại sao lại sửa chữa mã nếu nó không bị hỏng? Có một vài lý do để bạn có thể muốn tái cấu trúc mã. Đầu tiên là bắt nguồn của câu chuyện cổ tích: cơ sở mã rất cổ của sản phẩm đáng kính được kế thừa hoặc nếu không thì xuất hiện bí ẩn. Nhóm phát triển ban đầu đã biến mất. Một phiên bản mới, với các tính năng mới, phải được tạo ra, nhưng mã không còn hiểu được nữa. Nhóm phát triển mới, làm việc cả đêm lẫn ngày, giải mã nó, vẽ bản đồ nó và sau nhiều kế hoạch và thiết kế, phá hỏng mã hoàn toàn. Cuối cùng, cẩn thận, họ đặt nó tất cả trở lại với nhau theo tầm nhìn mới. Đây là tái cấu trúc trên quy mô khác thường và một ít vẫn còn hoạt động để nói về chuyện này. Một kịch bản thực tế hơn là một yêu cầu mới được đưa vào cho dự án đòi hỏi thay đổi thiết kế. Thật là vụn vặt cho dù yêu cầu này đã được đưa vào do sơ xuất trong kế hoạch ban đầu hoặc do cách tiếp cận lặp lại (chẳng hạn như phát triển nhanh nhẹn hoặc phát triển dựa vào thử nghiệm) đang được sử dụng để thận trọng đưa vào các yêu cầu trong suốt quá trình phát triển. Đây là tái cấu trúc trên một quy mô nhỏ hơn nhiều và nó thường yêu cầu thay đổi hệ thống phân cấp lớp, có lẽ do đưa vào các giao diện hoặc lớp trừu tượng, chia tách các lớp, sắp xếp lại các lớp và v.v. Một lý do cuối cùng để tái cấu trúc, khi các công cụ tái cấu trúc tự động có sẵn, chỉ đơn giản là một phím tắt để tạo mã ở vị trí đầu tiên một cái gì đó giống như cách sử dụng một chương trình kiểm tra lỗi chính tả (spellchecker) để phân loại một từ khi bạn không chắc cách đánh vần nó. Việc sử dụng tái cấu trúc nhàm chán này chẳng hạn để tạo ra các phương thức getter và setter có thể là một bộ tiết kiệm thời gian hiệu quả một khi bạn đã quen thuộc với các công cụ này. Các công cụ tái cấu trúc của Eclipse không được dự kiến để sử dụng cho phép tái cấu trúc tại một quy mô khác thường một vài công cụ có nhưng chúng là vô giá để làm thay đổi mã trong quá trình diễn biến của một ngày làm việc của lập trình viên trung bình, cho dù điều đó liên quan đến các kỹ thuật phát triển nhanh nhẹn hay không. Cuối cùng, bất kỳ hoạt động phức tạp nào có thể được tự động hóa đều là nhàm chán, cần tránh. Việc biết các công cụ tái cấu trúc Eclipse có sẵn những gì và cách sử dụng đã dự kiến của chúng, sẽ cải thiện rất nhiều năng suất của bạn. Có hai cách quan trọng để bạn có thể làm giảm nguy cơ làm hỏng mã. Một cách là phải có một bộ đầy đủ các bài thử nghiệm bộ phận cho mã đó: mã phải vượt qua các bài thử nghiệm cả trước và sau khi tái cấu trúc. Cách thứ hai là sử dụng một công cụ tự động hoá, chẳng hạn như các tính năng tái cấu trúc của Eclipse, để thực hiện phép tái cấu trúc này. Cách kết hợp thử nghiệm kỹ lưỡng và tái cấu trúc tự động đặc biệt mạnh mẽ và đã chuyển nghệ thuật bí ẩn này thành một công cụ thường ngày, có ích. Khả năng thay đổi cấu trúc mã của bạn mà không cần thay đổi chức năng của nó, theo cách nhanh chóng và an toàn, thêm chức năng hoặc cải thiện việc bảo trì của nó có thể ảnh hưởng đáng kể đến cách bạn thiết kế và phát triển mã, cho dù bạn kết hợp nó vào một phương thức nhanh nhẹn chính thức hay không. Các kiểu tái cấu trúc trong Eclipse Các công cụ tái cấu trúc của Eclipse có thể được nhóm lại thành ba thể loại rõ ràng (và đây là thứ tự mà chúng xuất hiện trong trình đơn Refactoring): 1. Thay đổi tên và tổ chức vật lý của mã, bao gồm đổi tên các trường, các biến, các lớp và các giao diện và di chuyển các gói và các lớp. 2. Thay đổi tổ chức logic của mã ở mức lớp, gồm việc chuyển các lớp ẩn danh thành các lớp lồng nhau, chuyển các lớp lồng nhau thành các lớp mức cao nhất, tạo ra các giao diện từ các lớp cụ thể và di chuyển các phương thức hoặc các trường từ một lớp đến lớp con hoặc siêu lớp. 3. Thay đổi mã trong một lớp, gồm chuyển các biến chuyển địa phương thành các trường lớp, chuyển mã chọn trong phương thức thành một phương thức tách biệt và tạo ra các phương thức getter và setter cho các trường. Một số phép tái cấu trúc gần như không khớp với ba thể loại này, đặc biệt là Thay đổi chữ kí phương thức (Change Method Signature), có trong thể loại thứ ba ở đây. Ngoài những trường hợp ngoại lệ này, các phần theo sau sẽ thảo luận về các công cụ tái cấu trúc của Eclipse theo thứ tự này. Tổ chức lại và đổi tên lại vật lý Bạn rõ ràng có thể đổi tên hoặc di chuyển các tệp xung quanh trong hệ thống tệp mà không cần một công cụ đặc biệt, nhưng làm như vậy với các tệp mã nguồn Java có thể đòi hỏi bạn phải chỉnh sửa nhiều tệp để cập nhật các câu lệnh import (nhập khẩu) hoặc package (gói). Tương tự như vậy, bạn có thể dễ dàng đổi tên các lớp, các phương thức và các biến bằng cách sử dụng một trình soạn thảo văn bản để tìm kiếm và thay thế chức năng, nhưng bạn cần phải làm điều này cẩn thận, vì các lớp khác nhau có thể có các phương thức hoặc các biến cùng tên; có thể rất nhàm chán để duyệt qua tất cả các tệp trong một dự án để đảm bảo chắc chắn rằng mọi cá thể được xác định và được thay đổi chính xác. Di chuyển và Đổi tên (Rename and Move) của Eclipse có thể thực hiện các thay đổi này một cách thông minh, trong suốt toàn bộ dự án, mà không có sự can thiệp của người dùng, vì Eclipse hiểu mã theo ngữ nghĩa và có thể xác định các tham chiếu đến một phương thức, biến cụ thể, hoặc các tên lớp. Việc thực hiện nhiệm vụ này dễ dàng giúp đảm bảo rằng phương thức, biến và các tên lớp thể hiện rõ ràng ý định của chúng. Thật dễ dàng tìm ra mã có các tên không phù hợp hoặc gây hiểu nhầm vì mã đã được thay đổi để thực hiện khác so với kế hoạch ban đầu đã lập. Ví dụ, một chương trình tìm kiếm các từ cụ thể trong một tệp có thể được mở rộng để làm việc với các trang Web bằng cách sử dụng lớp URL để có được một InputStream (luồng đầu vào). Nếu trước tiên người ta đã gọi file (tệp) cho luồng đầu vào này, thì nó cần được thay đổi để phản ánh tính chất tổng quát mới hơn của nó, có lẽ là sourceStream (luồng nguồn). Các nhà phát triển thường không tạo ra các thay đổi như thế này vì nó có thể là quá trình lộn xộn và nhàm chán. Tất nhiên, điều này làm cho mã khó hiểu với nhà phát triển tiếp theo, tức người phải tiếp tục làm việc với nó. Để đổi tên một phần tử Java, chỉ cần nhấn vào nó trong khung nhìn Package Explorer (Trình thám hiểm gói) hoặc chọn nó trong một tệp nguồn Java, sau đó chọn Refactor > Rename. Trong hộp thoại, chọn tên mới và chọn xem Eclipse có cần thay đổi các tham chiếu đến tên không. Các trường chính xác được hiển thị tùy thuộc vào kiểu phần tử mà bạn chọn. Ví dụ, nếu bạn chọn một trường có phương thức getter và setter, bạn cũng có thể cập nhật các tên của các phương thức này để phản ánh trường mới. Hình 1 chỉ ra một ví dụ đơn giản. Hình 1. Đổi tên một biến địa phương Giống như tất cả các phép tái cấu trúc Eclipse, sau khi bạn đã xác định mọi thứ cần thiết để thực hiện tái cấu trúc, bạn có thể nhấn Preview (Xem trước) để xem sự thay đổi mà Eclipse đề xuất thực hiện, trong một hộp thoại so sánh, nó cho phép bạn bác bỏ hoặc chấp nhận từng thay đổi trong mỗi tệp bị tác động tới. Nếu bạn tin vào khả năng của Eclipse để thay đổi đúng, bạn có thể chỉ cần nhấn OK. Tất nhiên, nếu bạn không chắc chắn phép tái cấu trúc sẽ làm gì, trước tiên bạn sẽ muốn xem trước, nhưng với các phép tái cấu trúc đơn giản như Đổi tên và Di chuyển thì điều này thường không cần thiết. Di chuyển thực hiện rất nhiều việc giống như với Đổi tên: Bạn chọn một phần tử Java (thường là một lớp), xác định vị trí mới của nó và xác định liệu các tham khảo có nên được cập nhật không. Sau đó bạn có thể chọn Preview để kiểm tra các thay đổi hoặc nhấn OK để thực hiện ngay lập tức phép tái cấu trúc như trong Hình 2. Hình 2. Di chuyển một lớp từ một gói này sang một gói khác Trên một số nền tảng (đặc biệt là Windows), bạn cũng có thể di chuyển các lớp từ một gói hoặc thư mục đến gói hoặc thư mục khác bằng cách kéo và thả chúng vào khung nhìn Package Explorer. Tất cả các tài liệu tham khảo sẽ được cập nhật tự động. Định nghĩa lại các mối quan hệ lớp Một tập nhiều phép tái cấu trúc của Eclipse cho phép bạn thay đổi các mối quan hệ lớp của bạn tự động. Các phép tái cấu trúc này không có ích lợi chung như các kiểu tái cấu trúc mà Eclipse phải cung cấp, nhưng có giá trị vì chúng thực hiện nhiệm vụ khá phức tạp. Khi chúng được dùng, chúng rất có ích. Tăng cường lớp ẩn danh và lồng nhau Hai phép tái cấu trúc, Chuyển đổi lớp ẩn danh thành lớp lồng nhau (Convert Anonymous Class to Nested) và Chuyển đổi lớp lồng nhau tới lớp mức cao nhất (Convert Nested Type to Top Level), là như nhau trong đó chúng di chuyển một lớp ngoài hướng của nó tới nơi có cơ hội để bao bọc. Lớp ẩn danh là loại viết nhanh cú pháp, cho phép bạn thuyết minh một lớp thực hiện một lớp hay giao diện trừu tượng ở nơi bạn cần đến nó, không cần phải cho nó một tên lớp rõ ràng. Điều này thường được sử dụng khi tạo các người nghe trong giao diện người sử dụng chẳng hạn. Trong Liệt kê 1, giả định rằng Bag là một giao diện được định nghĩa ở nơi khác để khai báo hai phương thức, get() và set(). Liệt kê 1. Lớp Bag public class BagExample { void processMessage(String msg) { Bag bag = new Bag() { Object o; public Object get() { return o; } public void set(Object o) { this.o = o; } }; bag.set(msg); MessagePipe pipe = new MessagePipe(); pipe.send(bag); } } Khi lớp ẩn danh trở nên lớn đến mức mã trở nên khó đọc, bạn nên nghĩ đến việc tạo cho lớp ẩn danh một lớp thích hợp; để giữ gìn sự bao bọc (nói cách khác, để ẩn giấu nó khỏi các lớp bên ngoài không cần biết về nó), bạn nên tạo cho lớp này một lớp lồng nhau chứ không phải là một lớp cao nhất. Bạn có thể làm điều này bằng cách nhấn vào bên trong lớp ẩn danh và chọn Refactor > Convert Anonymous Class to Nested. Nhập tên cho lớp này, chẳng hạn như BagImpl, khi được nhắc và sau đó chọn Preview hoặc OK. Việc này sẽ thay đổi mã như trong Liệt kê 2. Liệt kê 2. Lớp Bag được tái cấu trúc public class BagExample { private final class BagImpl implements Bag { Object o; public Object get() { [...]... được chọn, xem Hình 6 Hình 6 Không thay thế tất cả các thể hiện của biểu thức được chọn Tiếp theo, lặp lại phép tái cấu trúc này cho cuộc gọi thứ hai tới st.nextToken(), lúc này gọi biến địa phương mới value Liệt kê 10 cho thấy mã đó sau hai phép tái cấu trúc này Listing 10 Mã được tái cấu trúc private static void addProp(Properties props, String s) { StringTokenizer st = new StringTokenizer(s, "=");... kê 11 Liệt kê 11 Mã được tái cấu trúc public class Extract { private static final String DEFINE = "-D"; public static void main(String[] args) { Properties props = new Properties(); for (int i = 0; i < args.length; i++) { if (args[i].startsWith(DEFINE)) { String s = args[i].substring(2); addProp(props, s); } } } // Đối với mỗi tái cấu trúc Lấy ra (Extract ), có một tái cấu trúc Nội tuyến (Inline... Refactor > Convert Nested Type to Top Level Phép tái cấu trúc này sẽ yêu cầu bạn cung cấp một tên cho cá thể kèm theo Nó có thể đưa ra đề nghị, như example (ví dụ), mà bạn có thể chấp nhận Ý nghĩa của việc này sẽ được làm rõ trong giây lát Sau khi nhấn OK, mã cho lớp BagExample kèm theo sẽ được thay đổi như thể hiện trong Liệt kê 3 Liệt kê 3 Lớp Bag được tái cấu trúc public class BagExample { void processMessage(String... mã trong một lớp Sự đa dạng lớn nhất của các phép tái cấu trúc là việc tổ chức lại mã trong một lớp Trong số các việc khác, các việc này cho phép bạn đưa vào (hoặc loại bỏ) các biến trung gian, tạo ra một phương thức mới từ một phần của phương thức cũ, và tạo ra các phương thức getter và setter cho một trường Lấy ra và nội tuyến Có một số phép tái cấu trúc bắt đầu bằng từ Lấy ra (Extract): Lấy ra phương... 3 Thêm các thành viên cần thiết Sau khi nhấn OK, trường motor và các phương thức getMotor() và setMotor() sẽ được chuyển đến lớp Automobile Liệt kê 7 cho thấy hình dạng của lớp Automobile sau phép tái cấu trúc này Liệt kê 7 Lớp Automobile được tái cấu trúc public class Automobile extends Vehicle { private String make; private String model; protected String motor; public String getMake() { return make;... hằng số, tĩnh, phép tái cấu trúc sẽ chuyển đổi nó sang một hằng số tĩnh cuối cùng Điều này có ích để loại bỏ các số và các chuỗi mã hoá cứng khỏi mã của bạn Ví dụ, trong mã ở trên, chúng ta đã sử dụng -D" cho các tùy chọn dòng lệnh đang xác định một cặp giá trị tên Hãy làm nổi bật -D" trong mã đó, chọn Refactor > Extract Constant, và nhập DEFINE làm tên của hằng số đó Phép tái cấu trúc này sẽ thay đổi... tới các thành viên của lớp bên ngoài Để duy trì chức năng này, phép tái cấu trúc sẽ bổ sung một cá thể của lớp BagExample kèm theo vào lớp đã lồng nhau trước đây Đây là biến của cá thể mà trước đây bạn đã được yêu cầu cung cấp một tên cho nó Nó cũng tạo ra một hàm tạo để thiết lập biến của cá thể này Lớp mới BagImpl do phép tái cấu trúc tạo ra được hiển thị trong Liệt kê 4 Liệt kê 4 Lớp BagImpl final... Trường hợp thứ hai là nếu có một đoạn mã riêng biệt theo logic có thể được tái sử dụng bởi các phương thức khác Ví dụ, đôi khi bạn thấy mình đang lặp lại một vài dòng mã của một số phương thức khác Đó là một khả năng trong trường hợp này, nhưng có thể bạn sẽ không thực hiện phép tái cấu trúc này cho đến khi bạn thực sự cần tái sử dụng mã này Giả sử có một nơi khác mà bạn cần phải phân tích cú pháp... Getter and Setter Việc này sẽ hiển thị hộp thoại với các phương thức getter và setter được đề xuất cho từng trường, mà đã không chỉ có một trường Đây không phải là tái cấu trúc, tuy nhiên, bởi vì nó không cập nhật các tham khảo tới các trường để sử dụng các phương thức mới, bạn sẽ cần phải có trường đó cho mình nếu cần thiết Tùy chọn này là một bộ tiết kiệm thời gian quan trọng, nhưng tốt nhất nó thường... public interface Motorized { public abstract String getMotor(); public abstract void setMotor(String string); } Và việc khai báo lớp cho Automobile được thay đổi như sau: public class Automobile extends Vehicle implements Motorized Sử dụng một siêu kiểu (supertype) Phép tái cấu trúc cuối cùng có trong thể loại này là Sử dụng siêu kiểu ở nơi có thể (Use Supertype Where Possible) Hãy xem xét một ứng dụng quản . dụng từng tính năng. Lí do cần tái cấu trúc? Tái cấu trúc (Refactoring) là thay đổi cấu trúc của một chương trình mà không làm thay đổi chức năng của nó. Tái cấu trúc là một kỹ thuật mạnh, nhưng. Một tập nhiều phép tái cấu trúc của Eclipse cho phép bạn thay đổi các mối quan hệ lớp của bạn tự động. Các phép tái cấu trúc này không có ích lợi chung như các kiểu tái cấu trúc mà Eclipse phải. Tái cấu trúc cho mọi người Làm thế nào và tại sao lại sử dụng các tính năng tái cấu trúc được tự động hóa của Eclipse David Gallardo, Tư