b. Trình khách Globe.
3.4. Khả năng đăng ký một listener (unicast) và nhiều listener (multicast) của thành phần JavaBean
Bài giảng COP – Chuyên ngành: CNPM - Version 1
Biên soạn: Ngô Thị Lan & Nguyễn Lan Oanh - 120
Với ví dụ trên (useMouseBean.java) ta đã tạo ra hai đối tượng listener là mouseListener1 và mouseListener2 để đón bắt cùng một tình huống mousePressed do thành phần MouseBean gửi đến. Cơ chế cho phép nhiều listener cùng được đăng ký để xử lý một tình huống được gọi là multicast. Tuy nhiên với cơ chế này đôi lúc sẽ dẫn đến những trường hợp xâm phạm lẫn nhau, chẳng hạn listener này cho phép thay đổi trị của biến trong khi listener khác lại ngăn cản. Chính vì vậy một vài thành phần JavaBean chỉ cho phép đăng ký xử lý một tình huống mà thơi (unicast), nếu có nhiều hơn một tình huống được đăng ký thì phương thức đăng ký của thành phần JavaBean sẽ được thiết kế để ném ra ngoại lệ là TooManyListenersException như sau:
public void add<EventListenerType> (<EventListenerType> lsn) throw TooManyListenerException
Đoạn chương trình sau sẽ tạo ra hai phương thức add và remove chỉ cho phép đăng ký một listener mà thôi:
MouseListener saveListener=null;
/*Phương thức này dùng để các thành phần khác đăng ký đối tượng listener*/
public void addMouseListener ( MouseListener 1sn) throws TooManyListenerException{
if ( saveListener = = null) {
// Nếu chưa có đối tượng listener nào thì cho phép đăng ký saveListener=lsn;
} else {
// Nếu đã có rồi thì khơng cho phép bằng cách ném ra ngoại lệ throw ( new TooManyListenersException ( ) )
}
}// Phương thức này dùng để các thành phần khác loại bỏ đối tượng listener
public void removeMouseListener ( MouseListener lsn) { saveListener = null;
Bài giảng COP – Chuyên ngành: CNPM - Version 1
Biên soạn: Ngô Thị Lan & Nguyễn Lan Oanh - 121
Để hiểu rõ hơn, dưới đây ta sẽ viết một ví dụ minh họa cho sự tranh chấp khi có nhiều đối tượng listener cùng đăng ký xử lý một tình huống. Chương trình này dùng lại thành phần JavaBean B đã thiết kế ở phần đầu ( xem ví dụ về các thuộc tính ràng buộc – contrant property). Thuộc tính size của thành phần JavaBeans B là thuộc tính bị ràng buộc, trước khi thay đổi trị của thuộc tính nó đều phải hỏi ý kiến thông qua một listener. Để minh họa ta sẽ tạo hai đối tượng listener là myListenerB21 chỉ cho phép thay đổi thuộc tính size khi giá trị mới >50 còn myListenerB22 sẽ cho phép thay đổi thuộc tính size khi giá trị mới >100. Chương trình dùng 2 đối tượng listener cùng xử lý một tình huống.
Ví dụ 2-7: useBean2.java
import java.beans.*; public class useBeanB2 {
public static void main ( string args [] ) { // Tạo thành phần JavaBean B
B bean = new B ( );
// Gắn đối tượng listener theo dõi sự thay dổi của thuộc tính size bean.addSizeListener ( new myListenerB21 ( ) );
// Gắn đối tượng listener khác cùng theo dõi sự thay đổi của thuộc tính
size
bean.addSizeListener ( new myListenerB22 ( ) );
// Thử thay đổi thuộc tính size
System.out.println (“old size “+bean.getSize ( )+” set new size 30” ); bean.setSize (30) ;
System.out.println (“>size after setting”
+bean.getSize ( ) );
System.out.println (“old size “+bean.getSize ( ) +” set new size 90” ); // Thử thay đổi thuộc tính size
bean.setSize (90) ;
System.out.println (“>size after setting”+bean.getSize ( ) ); }
}
Bài giảng COP – Chuyên ngành: CNPM - Version 1
Biên soạn: Ngô Thị Lan & Nguyễn Lan Oanh - 122 // ( cho phép thay đổi khi giá trị mới của thuộc tính size > 50
class myListenerB21 implements VetoableChangeListener { public void vetoableChange (
propertyChangeEvent evt )
throw propertyVetoException {
Integer newVal= (Integer) evt.getNewValue ( ); if ( newVal.intValue ( ) > 50) {
throw (new propertyVetoException ( “ Greater than 50 Listener 1 reject “, evt )); }
} }
// Thiết kế đối tượng listener theo dõi sự thay đổi của thuộc tính size // ( cho phép thay đổi khi giá trị mới của thuộc tính size > 100) class myListenerB22 implements VetoableChangeListener { public void vetoableChange ( propertyChangeEvent evt )
throw propertyVetoException {
Integer newVal= (Integer) evt.getNewValue ( ); if ( newVal.intValue ( ) > 100) {
throw (new propertyVetoException (
“ Greater than 100 Listener 1 reject “, evt )); } } } Biên dịch: C:\Learning>java useBeanB2.java Chạy chương trình: C:\Learning>java useBeanB2 old size 0 set new size 30 > size after setting 30 old size 30 set new size 90
java.bean.PropertyVetoException: Greater than 50 Listener 1 reject
Bài giảng COP – Chuyên ngành: CNPM - Version 1
Biên soạn: Ngô Thị Lan & Nguyễn Lan Oanh - 123
> size after setting 30
Quan sát kết quả trả về ta sẽ thấy tất cả các giá trì >50 đều không gán được cho thuộc tính size, mặc dù listener thứ hai là myListenerB22 cho phép gán các giá trì >50 và <100 nhưng listener thứ nhất là myListenerB21 lại không cho phép, như vậy trong trường hợp Listener thứ hai là myListenerB22 cài đặt mà khơng biết rằng myListenerB21 đã được cài đặt trước đó thì người dùng cuối sẽ dễ bị nhầm lẫn.
Chính vì vậy mà java phân biệt hai cách đăng ký cho listener là unicast và multicast. Tuy nhiên theo khuyến khích thì các thành phần JavaBeans nên được xâu dựng hỗ trợ cho cơ chế đăng ký nhiều listener ( multicast), như vậy sẽ dễ tương thích với các phiên bản mới sau này của Java hơn