Một vài thủ thuật với generic


Một vài thủ thuật với generic:

Tự động ép kiểu:
Trong nhiều tình huống lập trình, vì đặc điểm chung của hệ thống, một số hệ thống chỉ trả về kiểu nguyên thủy Object, và yêu cầu khi lập trình người sử dụng phải cast nó về đúng kiểu mong muốn, thao tác này lặp đi lặp lại khá thường xuyên khi bạn lập trình trên những framework hiện đại nhất hiện nay, tiêu biểu có Hibernate, Spring.

Giả sử tôi khai báo một bean trong IoC container của Spring như sau:

<bean id="loggingDAO" class="com.demo.dao.impl.LoggingDAOImpl"></bean>
Trong khai báo của tôi, tôi đã đặt một bean với id là loggingDAO và trả về kiểu là LoggingDAOImpl.
Và chúng ta lấy ra bean này bằng đoạn mã sau:
Tôi tạo một findBean đặt trong FactoryServiceFinder như sau:

public final class FactoryServiceFinder {

private FactoryServiceFinder() {
}

public static Object findBean(String beanName) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(XML-FILE);
return appContext.getBean(beanName);
}

}

//loggingDAO là interface được cài đặt bởi LoggingDAOImpl.
LoggingDAO loggingDAO = (LoggingDAO)FactoryServiceFinder.findBean("loggingDAO");
//Sử dụng loggingDAO.
...........................

Chuyện này rất bình thường và lặp đi lặp lại nhiều lần, khi bạn binding trực tiếp nó trong JSF hay một framework cũng hỗ trợ quản lý bean bằng IoC container bạn sẽ không quan tâm đến việc ép kiểu này, nhưng trong khá nhiều trường hợp ví dụ như :
  • Lấy một bean từ Spring.
  • Cast một object từ request, session...etc.
  • Ngoài ra còn gặp ở một số container khác.

Tôi luôn tự hỏi tại sao tôi cứ phải làm công việc nhàm chán là đi cast lại Object như thế, thông thường khi tôi sử dụng getBean LoggingDAO đương nhiên tôi mong muốn kiểu trả về là LoggingDAO. Lẽ ra tôi chỉ cần thế này:

LoggingDAO loggingDao = FactoryServiceFinder.findBean("LoggingDAO");

Và thông qua Generic tôi đã giả quyết vấn đề như thế này:

/**
* <strong>Finding bean that config in IOC container.</strong><br/>
*Auto revert type.
*/
public class FactoryServiceFinder {
/**
* None Initial.
*/
private FactoryServiceFinder() {
}

/**
* Find a bean in IOC Container.
*
* @param <T>
* class type to return.
* @param beanName
* String bean name in file configuration.
* @return due to type of class want to return.
*/
public static <T> T findBean(String beanName) {
//Khởi tạo appContext.

final Object o = appContext.getBean(beanName);
final T returnedObject = (T) o;
return returnedObject;
}

}

Vấn đề đã được giả quyết, trước khi trả dữ liệu về, nó sẽ cố gắng cast về đúng loại object mà nó gán về.


Tham số động trong phương thức:
Nếu bạn đã từng làm qua Visual Basic 6.0 có lẽ bạn đã gặp qua vấn đề này, trong ngôn ngữ giả hướng đối tượng của VB6 nó giúp cho chúng ta truyền một tham số động như sau:
sum(num1, num2,....) bạn có thể truyền bao nhiêu tham số tùy ý.

Bây giờ mời bạn trở lại vấn đề:
Tôi muốn viết một chương trình cộng số, xưa nay tôi sẽ viết như thế này

Đoạn mã 1:
public int sum(int num1, int num2) {
return num1 + num2;
}

Nhưng bây giờ một anh bạn kia muốn cộng 3 số thì sao nào, không thành vấn đề, chẳng lẽ anh không biết trong java có overload à.

Đoạn mã 2:
public int sum(int num1, int num2, int num3) {
return num1 + num2+num3;
}

Thế cộng 4 số thì sao nào, 5 số, 6 số, tới đây tôi muốn nổi khùng rồi. À, tại sao chúng ta không dùng mảng nhỉ, rất tuyệt.

Đoạn mã 3:
public int sum(int[] num){
int result=0;
for(int i=0; i<num.length; i++){
result=result+num[i];
}
return result;
}

Rất tốt, xưa nay tôi vẫn dùng cách này, vấn đề là trước khi tôi muốn dùng, tôi cứ phải tạo 1 cái mảng cho nó, thật bất tiện, và thực sự cái code như thế này nhiều khi dài dòng lắm.
Tôi có một cách viết khác:

Đoạn mã 4:
public int sum(int... num){
int result=0;
for(int i=0; i<num.length; i++){
result=result+num[i];
}
return result;
}
Sử dụng:

public static void main(String[] args) {
Main m = new Main();
int result=m.sum(1,2,3,4,5,6,7,8);//Truyền số tham số tùy ý.
System.out.println(result);
}

Kỳ thực, Đoạn mã 3Đoạn mã 4 là giống nhau, nó chỉ là 2 cách thể hiện khác nhau mà thôi, với cách viết của đoạn mã 3, bạn hoàn toàn vẫn có thể dùng hình thức truyền nhiều tham số bình thường như đoạn mã 4. Trình biên dịch java sẽ báo lỗi khi sử dụng đoạn mã 3 và 4 chung trong 1 Class.
Và int... được xem là int[] nên nó sẽ không có vấn đề gì khi bạn overload một hàm 2, 3 tham số với tham số là array, nó sẽ chọn đúng phương thức của bạn để thi hành, nếu gọi hàm 2 tham số, nó dùng hàm 2 tham số, 3 tham số, nó dùng hàm 3 tham số, nếu 4, 5 tham số, nó dùng mảng.
Tôi ứng dụng nó trong trường hợp truyền các tham số động, các hàm database là trường hợp tôi đặc biệt ưa thích, Hibernate cũng làm như vậy.

About Langthang

This is a short description in the author block about the author. You edit it by entering text in the "Biographical Info" field in the user admin panel.
    Blogger Comment
    Facebook Comment

1 comments :