Động lực học lập trình Java - Phần 3: Ứng dụng sự phản chiếu

Tóm tắt: Xử lý đối số dòng lệnh là một trong những việc vặt khó chịu mà dường

như vẫn tiếp tục xảyra xung quanh bất kể bạn đã phải giải quyết nó mất bao nhiêu

lần trong quá khứ. Thay vì viết các thay đổi của cùng mã lặp đi lặp lại, tại sao

không sử dụng sự phản chiếu để đơn giản hóa công việc xử lý đối số? Nhà tư vấn

Java Dennis Sosnoski chỉ cho bạn thấy cách làm thế nào. Trong bài này, Dennis

phác thảo một thư viện mã nguồn mở, cho phép tạo các đối số dòng lệnh để tự xử

lý trên thực tế.

pdf16 trang | Chuyên mục: Java | Chia sẻ: dkS00TYs | Lượt xem: 1855 | Lượt tải: 0download
Tóm tắt nội dung Động lực học lập trình Java - Phần 3: Ứng dụng sự phản chiếu, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
ic static void main(String[] args) { 
 // if no arguments are supplied, assume help is needed 
 if (args.length > 0) { 
 // process arguments directly to instance 
 PlanGen inst = new PlanGen(); 
 int next = ArgumentProcessor.processArgs 
 (args, PARM_DEFS, inst); 
 // next unused argument is output file name 
 if (next >= args.length) { 
 System.err.println("Missing required output file name"); 
 System.exit(1); 
 } 
 File outf = new File(args[next++]); 
 ... 
 } else { 
 System.out.println("\nUsage: java PlanGen " + 
 "[-options] file\nOptions are:\n c concise plan\n" + 
 "f first year revenue (K$)\n g growth rate\n" + 
 "n product description"); 
 } 
 } 
} 
Phần duy nhất còn lại là việc xử lý tạo báo cáo lỗi (chẳng hạn như một ký tự cờ 
tham số không rõ hoặc một giá trị số ngoài dải). Với mục đích này, tôi sẽ xác định 
ArgumentErrorException như là một lỗi ngoại lệ không được kiểm tra được đưa ra 
nếu một trong các lỗi này xảy ra. Nếu lỗi ngoại lệ này không được nhận ra, nó sẽ 
ngay lập tức làm hỏng ứng dụng với một thông báo lỗi và vết tích ngăn xếp được 
kết xuất trên bàn điều khiển. Như là một sự lựa chọn, bạn có thể nhận ra lỗi ngoại 
lệ này trực tiếp trong mã của bạn và xử lý nó bằng một số cách khác (ví dụ, có thể 
in ra các thông báo lỗi thực tế cùng với việc thông tin về cách sử dụng). 
Thực hiện thư viện 
Đối với thư viện để sử dụng sự phản chiếu như đã lập kế hoạch, cần phải tìm kiếm 
các trường được xác định bằng mảng các định nghĩa tham số và sau đó lưu trữ các 
giá trị thích hợp tới các trường này từ các đối số dòng lệnh tương ứng. Nhiệm vụ 
này có thể được xử lý bằng cách tìm kiếm thông tin trường khi cần thiết cho các 
đối số dòng lệnh thực tế, nhưng thay vào đó tôi đã thực hiện một sự lựa chọn để 
tách việc tìm kiếm khỏi cách sử dụng. Tôi sẽ tìm thấy tất cả các trường trước, sau 
đó chỉ cần sử dụng thông tin đã được tìm thấy trong quá trình xử lý các đối số. 
Tìm trước tất cả các trường là một bước lập trình an toàn để loại bỏ một trong các 
vấn đề tiềm năng khi dùng phản chiếu. Nếu tôi chỉ tìm kiếm các trường khi cần 
thiết, thật dễ dàng để phá vỡ một định nghĩa tham số (ví dụ, bằng cách không gõ 
tên trường tương ứng) mà không nhận ra rằng có bất cứ điều gì đã sai. Sẽ không 
có các lỗi thời gian-dịch nào vì tên trường được chuyển qua như các String, và 
thậm chí chương trình sẽ thực hiện tốt miễn là không có đối số khớp với định 
nghĩa tham số bị ngắt đã được xác định trên dòng lệnh. Kiểu lỗi có đánh dấu này 
có thể dễ dàng làm cho việc chuyển dịch mã bị hỏng. 
Dựa vào đó tôi muốn tìm thông tin trường trước khi xử lý các đối số trên thực tế, 
Liệt kê 4 cho thấy việc thực hiện lớp cơ bản cho các định nghĩa tham với một 
phương thức bindToClass() để xử lý tìm kiếm trường. 
Liệt kê 4. Lớp cơ sở cho các định nghĩa tham số 
public abstract class ParameterDef 
{ 
 protected char m_char; // argument flag character 
 protected String m_name; // parameter field name 
 protected Field m_field; // actual parameter field 
 protected ParameterDef(char chr, String name) { 
 m_char = chr; 
 m_name = name; 
 } 
 public char getFlag() { 
 return m_char; 
 } 
 protected void bindToClass(Class clas) { 
 try { 
 // handle the field look up and accessibility 
 m_field = clas.getDeclaredField(m_name); 
 m_field.setAccessible(true); 
 } catch (NoSuchFieldException ex) { 
 throw new IllegalArgumentException("Field '" + 
 m_name + "' not found in " + clas.getName()); 
 } 
 } 
 public abstract void handle(ArgumentProcessor proc); 
} 
Việc thực hiện thư viện thực tế bao gồm một vài lớp ngoài những gì mà tôi đã đề 
cập trong bài viết này. Tôi sẽ không duyệt toàn bộ danh sách ở đây, vì hầu hết 
không liên quan đến khía cạnh phản chiếu của thư viện. Tôi sẽ đề cập đến những 
gì mà tôi đã chọn để lưu trữ đối tượng đích như là một trường của lớp 
ArgumentProcessor và thực hiện cài đặt thực tế một trường tham số trong lớp này. 
Cách tiếp cận này đưa ra một mẫu đơn giản cho việc xử lý đối số: lớp 
ArgumentProcessor quét các đối số để tìm các cờ tham số, tìm kiếm định nghĩa 
tham số tương ứng cho mỗi cờ (mà cờ đó sẽ luôn là một lớp con của 
ParameterDef) và gọi phương thức handle() của định nghĩa đó. Phương thức 
handle() lần lượt gọi một phương thức setValue() của ArgumentProcessor sau khi 
giải thích giá trị đối số. Liệt kê 5 cho thấy một phiên bản một phần của lớp 
ArgumentProcessor bao gồm các cuộc gọi liên kết tham số trong hàm tạo và 
phương thức setValue(): 
Liệt kê 5. Liệt kê một phần lớp thư viện chính 
public class ArgumentProcessor 
{ 
 private Object m_targetObject; // parameter value object 
 private int m_currentIndex; // current argument position 
 ... 
 public ArgumentProcessor(ParameterDef[] parms, Object target) { 
 // bind all parameters to target class 
 for (int i = 0; i < parms.length; i++) { 
 parms[i].bindToClass(target.getClass()); 
 } 
 // save target object for later use 
 m_targetObject = target; 
 } 
 public void setValue(Object value, Field field) { 
 try { 
 // set parameter field value using reflection 
 field.set(m_targetObject, value); 
 } catch (IllegalAccessException ex) { 
 throw new IllegalArgumentException("Field " + field.getName() + 
 " is not accessible in object of class " + 
 m_targetObject.getClass().getName()); 
 } 
 } 
 public void reportArgumentError(char flag, String text) { 
 throw new ArgumentErrorException(text + " for argument '" + 
 flag + "' in argument " + m_currentIndex); 
 } 
 public static int processArgs(String[] args, 
 ParameterDef[] parms, Object target) { 
 ArgumentProcessor inst = new ArgumentProcessor(parms, target); 
 ... 
 } 
} 
Cuối cùng, Liệt kê 6 cho thấy việc thực hiện một phần của lớp con định nghĩa 
tham số cho các giá trị tham số int. Điều này có cả việc ghi đè của phương thức 
bindToClass() lớp cơ sở (từ Liệt kê 4) phương thức này trước tiên gọi thực hiện 
lớp cơ sở và sau đó kiểm tra xem trường đã tìm thấy có ăn khớp với kiểu dự kiến 
không. Các lớp con cho các kiểu tham số cụ thể khác (boolean, float, String, v.v) 
là rất giống nhau. 
Liệt kê 6.Lớp định nghĩa tham số int 
public class IntDef extends ParameterDef 
{ 
 private int m_min; // minimum allowed value 
 private int m_max; // maximum allowed value 
 public IntDef(char chr, String name, int min, int max) { 
 super(chr, name); 
 m_min = min; 
 m_max = max; 
 } 
 protected void bindToClass(Class clas) { 
 super.bindToClass(clas); 
 Class type = m_field.getType(); 
 if (type != Integer.class && type != Integer.TYPE) { 
 throw new IllegalArgumentException("Field '" + m_name + 
 "'in " + clas.getName() + " is not of type int"); 
 } 
 } 
 public void handle(ArgumentProcessor proc) { 
 // set up for validating 
 boolean minus = false; 
 boolean digits = false; 
 int value = 0; 
 // convert number supplied in argument list to 'value' 
 ... 
 // make sure we have a valid value 
 value = minus ? -value : value; 
 if (!digits) { 
 proc.reportArgumentError(m_char, "Missing value"); 
 } else if (value m_max) { 
 proc.reportArgumentError(m_char, "Value out of range"); 
 } else { 
 proc.setValue(new Integer(value), m_field); 
 } 
 } 
} 
Đóng lại thư viện 
Trong bài viết này, tôi đã duyệt qua việc thiết kế một thư viện để xử lý các đối số 
dòng lệnh như một ví dụ về sự phản chiếu đang hoạt động. Thư viện này tạo ra 
một sự minh hoạ tốt về cách sử dụng sự phản chiếu có hiệu quả -- nó làm đơn giản 
mã ứng dụng mà không phải hy sinh hiệu năng đáng kể. Phải từ bỏ bao nhiêu hiệu 
năng? Trong một số phép thử nghiệm nhanh trên hệ thống phát triển của tôi, một 
chương trình thử nghiệm đơn giản đã lấy trung bình dài hơn khoảng 40 giây để 
thực hiện việc xử lý đối số khi sử dụng thư viện đầy đủ, như được so sánh với việc 
xử lý không có đối số nào. Phần lớn thời gian đó biểu diễn việc nạp các lớp thư 
viện và các lớp khác được mã thư viện sử dụng, vì vậy ngay cả với các ứng dụng 
có nhiều tham số dòng lệnh được định nghĩa và nhiều giá trị đối số, nó không thể 
xấu hơn điều này. Đối với các ứng dụng dòng lệnh của tôi, 40 giây thêm vào 
không phải là một cái gì đó mà tôi sắp thông báo. 
Mã thư viện đầy đủ có sẵn từ đường liên kết trong phần Tài nguyên. Nó bao gồm 
một số tính năng mà tôi đã để ngoài bài viết này, bao gồm nhiều điều thú vị như là 
kết nối để dễ dàng tạo ra một danh sách có định dạng của cờ và các mô tả tham số 
để giúp cung cấp các hướng dẫn cách sử dụng cho một ứng dụng. Bạn cứ việc sử 
dụng thư viện đó trong các chương trình của riêng bạn và mở rộng nó theo bất kỳ 
cách nào mà bạn thấy có ích. 
Bây giờ tôi đã trình bày các điều cơ bản của các lớp Java trong Phần 1 và các 
nguyên tắc Java Reflection API trong Phần 2 và Phần 3, phần còn lại của loạt bài 
này sẽ tránh đi theo con đường ít người qua lại về thao tác bytecode. Tôi sẽ bắt 
đầu dễ dàng trong Phần 4 với việc xem xét về thư viện Javassist thân thiện với 
người dùng để làm việc với các lớp nhị phân. Bạn có muốn thử các phương thức 
chuyển đổi không, chỉ là miễn cưỡng để bắt đầu lập trình theo bytecode? Javassist 
có thể chỉ là công cụ phù hợp với các nhu cầu của bạn. Hãy tìm hiểu Javassist là 
như thế nào vào tháng tới. 
Đôi nét về tác giả 
Dennis Sosnoski là một nhà tư vấn và nhà trợ giúp đào tạo chuyên về các dịch vụ 
Web và SOA dựa trên-Java. Kinh nghiệm phát triển phần mềm chuyên nghiệp của 
ông trải suốt hơn 30 năm qua, với một thập kỉ cuối tập trung vào các công nghệ 
XML và Java phía máy chủ. Dennis là nhà phát triển hàng đầu về dụng cụ liên kết 
dữ liệu XML JiBX mã nguồn mở, cũng là một người có duyên nợ với khung công 
tác của các dịch vụ Web Apache Axis2. Ông cũng là một trong những thành viên 
của nhóm chuyên gia đặc tả kỹ thuật của Jax-WS 2.0 và JAXB 2.0. Xem trang 
web của ông để có thông tin về các dịch vụ đào tạo và tư vấn của ông. 
Mục lục 
 Xác định vấn đề 
 Chọn giao diện 
 Thực hiện thư viện 
 Đóng lại thư viện 

File đính kèm:

  • pdfĐộng lực học lập trình Java, Phần 3 Ứng dụng sự phản chiếu.pdf
Tài liệu liên quan