TRƯỜNG CAO ĐẲNG CÔNG NGHỆ THÔNG TIN TP.HCM
LẬP TRÌNH ỨNG DỤNG MẠNG BÀI 1
JAVA BEANS JAVA BEANS
1
GIẢNG VIÊN: VÕ TẤN DŨNG
g n ũ D n ấ T õ V
:
V G
PHẦN 1 JavaBean Overview
2
g n ũ D n ấ T õ V
:
V G
COMPONENT MODEL COMPONENT MODEL
• Component là các thành phần độc lập của phần mềm được lắp ráp với nhau để hình thành một ứng dụng. Các component trong Java được gọi là Bean hay Java-Bean.
• Các component trong một ứng dụng có thể tương tác
với nhau. Để tương tác được với nhau thì các component phải được đặt trong một container. Container được gọi là environment. Bản thân container cũng là một component.
3
g n ũ D n ấ T õ V
:
V G
• Mỗi Bean đều có các thuộc tính (properties) và các hành vi (behaviors) cho phép Bean tương tác với environment và tương tác với các Bean khác.
CÁC KHÁI NIỆM TRONG BEAN CÁC KHÁI NIỆM TRONG BEAN
4
g n ũ D n ấ T õ V
:
V G
• Introspection (khám phá nội quan). • Properties (các thuộc tính). • Customization (sự tùy biến). • Events (các sự kiện). • Persistence (bảo tồn). • Methods (các phương thức).
PHẦN 2 Bean’s properties
5
g n ũ D n ấ T õ V
:
V G
THUỘC TÍNH CỦA BEAN (PROPERTIES) THUỘC TÍNH CỦA BEAN (PROPERTIES)
• Thuộc tính cho biết trạng thái (state) của một đối
tượng. Các thuộc tính được truy cập bằng tên của thuộc tính.
• Người dùng tương tác với bean thông qua các thuộc tính của nó. Bằng cách thay đổi thuộc tính, các nhà phát triển ứng dụng sẽ đem đến cho component một diện mạo và các hành vi khác.
• Thuộc tính của bean có thể được thay đổi bằng các dòng lệnh trong code hoặc bằng các công cụ trực quan (visual tools).
6
g n ũ D n ấ T õ V
:
V G
• Thuộc tính thật ra là nhưng biến nằm trong một lớp.
CÁC GETTER VÀ SETTER CÁC GETTER VÀ SETTER
• Thông thường biến được dùng vào hai mục đích đó là
gán dữ liệu vào và lấy dữ liệu ra.
• Giá trị của các thuộc tính không nên được truy cập trực tiếp mà cần phải thông qua các phương thức. • Các phương thức để đọc dữ liệu từ biến được gọi là các getter. Các phương thức để gán dữ liệu cho biến được gọi là các setter.
• Các thuộc tính có các tính chất sau: read-and-write,
read-only, write-only.
7
g n ũ D n ấ T õ V
:
V G
• Kiểu dữ liệu của một thuộc tính có thể là kiểu sơ cấp (primitive) như int, long, boolean,…hoặc kiểu dữ liệu đối tượng của một lớp nào đó (kiểu wrapper class).
CÁC GETTER VÀ SETTER CÁC GETTER VÀ SETTER
• Các setter và getter nên theo các mẫu thiết kế (design
pattern) sau đây:
– public void set
• Nếu
thể theo mẫu sau:
– public boolean is
– Xem trang 51,52/”Developing Java Bean”-Robert Englander – Xem mục 3.2 chương 9/”Java-tập 1”-Phương Lan
8
g n ũ D n ấ T õ V
:
V G
• Ví dụ:
Indexed properties Indexed properties
• Các phần tử của mảng được truy xuất nhờ vào chỉ số
– Setter:
• public
– Getter:
• public
cho nên những thuộc tính kiểu mảng được gọi là thuộc tính chỉ số (indexed properties). • Các mẫu thiết kế (design pattern):
– private Color[] standardColor={Color.white,Color.green,Color.red}; – public int getStandardColor(int idx); – public int setStandardColor(int idx, Color c);
9
g n ũ D n ấ T õ V
:
V G
• Ví dụ:
Bound properties Bound properties
• Khi thuộc tính của bean có thay đổi giá trị, nó có thể
báo cho các bean khác biết sự thay đổi đó bằng cách thông báo.
• Các thuộc tính có hỗ trợ các thông báo như vậy thì
được gọi là các bound properties (thuộc tính thể hiện sự thay đổi).
• Hoạt động này được thực hiện thông qua Event và các
10
g n ũ D n ấ T õ V
:
V G
Listener.
Bound properties Bound properties
• Một PropertyChangeEvent của một bounded property
chỉ được thông báo ra bên ngoài khi nó có sự thay đổi. Tức là sự kiện (event) về sự thay đổi đó đã xảy ra. • Nếu một bean có bound property thì nó phải cung cấp một hàm đăng ký (register) và một hàm gỡ bỏ đăng ký (unregister) tương ứng với một bộ lắng nghe sự kiện thuộc tính (PropertyChangeListener).
• Người lập trình có thể thiết kế và viết code cho các bộ
11
g n ũ D n ấ T õ V
:
V G
lắng nghe sự kiện thuộc tính này.
Bound properties Bound properties
– public void addPropertyChangeListener(PropertyChangeListener p); – public void removePropertyChangeListener(PropertyChangelistener p); • Trường hợp chỉ cần áp dụng cho một thuộc tính cụ thể
• Design Pattern cho các register và unregister:
thì ta cài đặt theo mẫu sau:
– public void add
12
g n ũ D n ấ T õ V
:
V G
• Ví dụ: một bean có thuộc tính size kiểu int thì: – public void addSizeListener(PropertyChangeListener p); – public void removeSizeListener(PropertyChangelistener p);
Bound properties Bound properties
Object newValue);
• Các register và unregister chỉ dùng để đăng ký và gỡ bỏ đăng ký các Listener mà thôi. Để các đối tượng Listener nhận biết được sự thay của thuộc tính thì ta phải xây dựng hàm firePropertyChange trong bean. – public void firePropertyChange(String propertyName, Object oldValue,
• Khi thiết kế bộ lắng nghe sự kiện thuộc tính (Property
Change Listener) thì ta cần cài đặt phương thức: – public void propertyChange(PropertyChangeEvent evt)
13
g n ũ D n ấ T õ V
:
V G
• Khi có sự kiện thay đổi thuộc tính xảy ra tại bean, hàm firePropertyChange của nó sẽ thông báo đến mọi đối tượng Listener đã đăng ký để Listener xử lý sự kiện bằng hàm propertyChange của Listener.
Bound properties VÍ DỤ: vềvề Bound properties VÍ DỤ:
14
g n ũ D n ấ T õ V
:
V G
• Ví dụ 9-1 và 9-2 chương 9/”Java-tập 1”-Phương Lan
Constrained properties Constrained properties
• Hạn chế của các bound properties là các listener phải chấp nhận giá trị thuộc tính đã thay đổi mà không được quyền từ chối.
• Trong một số thời điểm, listener có quyền từ chối
15
g n ũ D n ấ T õ V
:
V G
không chấp nhận sự thay đổi của một thuộc tính nào đó từ một bean. Các thuộc tính như vậy gọi là các thuộc tính ràng buộc (constrained properties).
Constrained properties Constrained properties
• Để đăng ký đối tượng Listener cho một thuộc tính ràng
buộc thì bean phải được cài đặt register và unregister
theo các mẫu sau:
– public void add
– public void addVetoableChangeListener(VetoableChangeListener p); – public void removeVetoableChangeListener(VetoableChangeListener p);
• Hoặc:
– public void fireVetoableChange(String propertyName, Object oldvalue,
Object newValue)
16
g n ũ D n ấ T õ V
:
V G
• Và hàm thông báo:
Constrained properties Constrained properties
• Để phản ứng lại với các thay đổi của constrained
property thì ta phải xây dựng các bộ lắng nghe sự kiện từ giao diện VetoableChangeListener với phương thức cần cài đặt là: – public void vetoableChange(PropertyChangeEvent evt)
• Nếu Listener không đồng ý cho thay đổi thuộc tính nó sẽ ném ra ngoại lệ PropertyVetoException. Thành phần bean có thuộc tính constraint sẽ bắt lấy và hủy bỏ quá trình thay đổi giá trị cho thuộc tính.
17
g n ũ D n ấ T õ V
• Đối tượng VetoableChangeSupport cũng tương tự
:
V G
như PropertyChangeSupport dùng để quản lý các đối tượng listener. PropertyChangeSupport được dùng cho bound property còn VetoableChangeSupport dùng cho constrained property.
Constrained properties VÍ DỤ: vềvề Constrained properties VÍ DỤ:
18
g n ũ D n ấ T õ V
:
V G
• Ví dụ 9-3 và 9-4 chương 9/”Java-tập 1”-Phương Lan
PHẦN 3 Introspection (khám phá nội quan)
19
g n ũ D n ấ T õ V
:
V G
KHÁI NIỆM INTROSPECTION KHÁI NIỆM INTROSPECTION
• Introspection là tiến trình phơi bày các thuộc tính
(properties), các phương thức (methods), các sự kiện (events) mà một Bean có thể hỗ trợ.
– Cơ chế phản ánh mức thấp (low-level reflection mechanism).
Hay còn được gọi là Introspector ngầm định. – Xây dựng BeanInfo class bên cạnh một Bean.
20
g n ũ D n ấ T õ V
:
V G
• Tiến trình này được dùng vào lúc run-time của chương trình hoặc bởi các công cụ phát triển trực quan (visual development tool) vào lúc design-time. • Có hai cách để thực hiện tiến trình này:
BeanInfo ClassClass BeanInfo
• Trong một số trường hợp, ta muốn phơi bày những
thuộc tính, sự kiện, phương thức của một Bean theo ý muốn hơn là dùng Introspetor ngầm định.
• Khi đó ta xây dựng một BeanInfo class dựa theo
BeanInfo interface.
• Bean class được thiết kế bên cạnh một Bean nhằm để
21
g n ũ D n ấ T õ V
:
V G
xác định các thông tin của Bean.
BeanInfo ClassClass BeanInfo
• Một BeanInfo class hiện thực giao tiếp
22
g n ũ D n ấ T õ V
:
V G
java.beans.BeanInfo xác định một tập các method được dùng để thu thập các thông tin về một Bean. Các method đó là:
Class (Bean Descriptor) BeanInfo Class (Bean Descriptor) BeanInfo
• Lớp java.beans.BeanDescriptor được dùng để mô tả
lớp hiện thực của Bean.
– public BeanDescriptor(Class beanClass) – public BeanDescriptor(Class beanClass, Class customizerClass)
• Cú pháp:
• Ví dụ: có một Bean tên là Thermostat được hiện thực
BeanDescriptor(BeansBook.Simulator.Thermostat.class);
23
g n ũ D n ấ T õ V
:
V G
bởi lớp Thermostat.class. Ta xây dựng Bean Descriptor cho nó như sau: – BeanDesciptor bd = new
Class (Bean Descriptor) BeanInfo Class (Bean Descriptor) BeanInfo
• Ví dụ: package BeansBook.Simulator; import java.beans.*;
public class ThermostatBeanInfo extends SimpleBeanInfo {
public BeanDescriptor getBeanDescriptor() {
BeanDescriptor bd = new BeanDescriptor(Thermostat.class); bd.setDisplayName("Simulated Thermostat"); return bd;
}
}
24
g n ũ D n ấ T õ V
:
V G
Class (Icon) BeanInfo Class (Icon) BeanInfo
Ví dụ:
• public java.awt.Image getIcon(int iconKind) {
if (iconKind == BeanInfo.ICON_COLOR_16x16) {
java.awt.Image img = loadImage("thermostat.gif"); return img;
} return null;
}
25
g n ũ D n ấ T õ V
:
V G
• Mỗi Bean cần có một Icon tương ứng để được các công cụ phát triển trực quan đặt Bean vào palettes hoặc tool-bars. Các icon này có định dạng là file ảnh GIF với các kích thước và màu sắc theo bảng sau:
Class (Property Descriptor) BeanInfo Class (Property Descriptor) BeanInfo • Property Descriptor được dùng để cung cấp các thông tin tường minh
về các thuộc tính sẽ được phơi bày.
• Design pattern 1: dùng cho các properties có setter và
throws IntrospectionException
getter chuẩn (có dạng getPropetyName và setPropertyName): – public PropertyDescriptor(String propertyName, Class beanClass)
• Design pattern 2: dùng cho các properties có setter và
getter không theo dạng chuẩn: – public PropertyDescriptor(String propertyName, Class beanClass, String getterName, String setterName) throws IntrospectionException
– public PropertyDescriptor(String propertyName, Method getter, Method
setter) throws IntrospectionException
26
g n ũ D n ấ T õ V
:
V G
• Design pattern 3:
Class (Property Descriptor) BeanInfo Class (Property Descriptor) BeanInfo
• Các vị dụ về Property Descriptor: Xem trang 156,157,158/”Developing Java Bean”-Robert
27
g n ũ D n ấ T õ V
:
V G
Englander
Indexed Property Descriptor Indexed Property Descriptor
• Cú pháp:
– public IndexedPropertyDescriptor(String propertyName, Class beanClass)
throws IntrospectionException
• Ví dụ: public PropertyDescriptor[ ] getPropertyDescriptors() {
try {
IndexedPropertyDescriptor ip =
new IndexedPropertyDescriptor("Stocks", WatchList.class);
PropertyDescriptor[ ] pda = { ip }; return pda;
} catch (IntrospectionException e) { return null; }
}
28
g n ũ D n ấ T õ V
:
V G
Indexed Property Descriptor Indexed Property Descriptor
Các dạng cú pháp khác: •
public IndexedPropertyDescriptor(
String propertyName, Class beanClass, String getterName, String setterName, String indexedGetterName, String indexedSetterName ) throws IntrospectionException
•
public IndexedPropertyDescriptor( String propertyName, Method getter,Method setter, Method indexedGetter, Method indexedSetter
)throws IntrospectionException
29
g n ũ D n ấ T õ V
:
V G
Method Descriptor Method Descriptor
• Method được phơi bày một cách đơn giản bằng cách thêm tiền tố public trước tên phương thức. Method Descriptor cho phép ta chỉ định một cách tường minh rằng method nào của một Bean sẵn có để được gọi.
– public MethodDescriptor(Method method) – public MethodDescriptor(
Method method, ParameterDescriptor parameterDescriptors[]
)
30
g n ũ D n ấ T õ V
:
V G
• Cú pháp:
Method Descriptor Method Descriptor
Ví dụ:
• public MethodDescriptor[ ] getMethodDescriptors() {
try {
Class c = WatchList.class; Method clear = c.getMethod("clearStocks", null); MethodDescriptor clearDesc = new MethodDescriptor(clear); clearDesc.setShortDescription("Clears the list of stocks"); Class[ ] params = { java.lang.Integer.TYPE }; Method sort = c.getMethod("sortStocks", params); ParameterDescriptor pd = new ParameterDescriptor(); pd.setShortDescription("Specifies the sort order"); ParameterDescriptor[ ] s = { pd }; MethodDescriptor sortDesc = new MethodDescriptor(sort, s); sortDesc.setShortDescription("Sorts the list of stocks"); MethodDescriptor[ ] mda = { clearDesc, sortDesc }; return mda;
} catch (SecurityException e) { return null; }
catch (NoSuchMethodException e) { return null; }
}
31
g n ũ D n ấ T õ V
:
V G
Event Set Descriptor Event Set Descriptor
• Event Set Descriptor phơi bày các sự kiện có thể sinh ra bởi một Bean. Nhiều event khác nhau có thể được nhóm vào một Event Set bằng cách nhóm theo các event methods trong cùng một Listener.
– public EventSetDescriptor( Class sourceClass, String eventSetName, Class listenerType, String listenerMethodName
) throws IntrospectionException
32
g n ũ D n ấ T õ V
:
V G
• Các cú pháp:
Event Set Descriptor Event Set Descriptor
)throws IntrospectionException
– public EventSetDescriptor( String eventSetName, Class listenerType, MethodDescriptor listenerMethodDescriptors[], Method addListenerMethod, Method removeListenerMethod
) throws IntrospectionException
– public EventSetDescriptor( String eventSetName, Class listenerType, Method listenerMethods[], Method addListenerMethod, Method removeListenerMethod
)throws IntrospectionException
33
g n ũ D n ấ T õ V
:
V G
• Các cú pháp (tiếp theo): – public EventSetDescriptor( Class sourceClass, String eventSetName, Class listenerType, String listenerMethodNames[], String addListenerMethodName, String removeListenerMethodName
Event Set Descriptor Event Set Descriptor
public EventSetDescriptor[] getEventSetDescriptors() {
try {
EventSetDescriptor ed = new EventSetDescriptor(Temperature.class, "Property Change Event", PropertyChangeListener.class, "propertyChange");
EventSetDescriptor[ ] eda = { ed } ; return eda;
} catch (IntrospectionException e) { return null; }
}
34
g n ũ D n ấ T õ V
:
V G
• Ví dụ 1:
Event Set Descriptor Event Set Descriptor
• Ví dụ 2:
public EventSetDescriptor[] getEventSetDescriptors() {
try {
String[] names = { "propertyChange" } ; EventSetDescriptor ed =
new EventSetDescriptor(Temperature.class, "Property Change Event", PropertyChangeListener.class, names, "addPropertyChangeListener", "removePropertyChangeListener");
EventSetDescriptor[ ] eda = { ed } ; return eda;
} catch (IntrospectionException e) { return null; }
}
35
g n ũ D n ấ T õ V
:
V G
PHẦN 4 EVENTS & LISTENERS (sự kiện & bộ lắng nghe sự kiện)
36
g n ũ D n ấ T õ V
:
V G
MÔ HÌNH SỰ KIỆN MÔ HÌNH SỰ KIỆN
• Các sự kiện là các thông điệp (messages) được gửi từ một đối tượng (Object) đến các đối tượng khác để thông báo với bên nhận rằng có điều gì đó đáng chú ý đã xảy ra. Phía bên nhận cần có một bộ lắng nghe sự kiện (listener) để xử lý (handle) sự kiện.
• Mô hình sự kiện (event model) của Java bao gồm:
event objects, event listeners, event sources.
37
g n ũ D n ấ T õ V
:
V G
• Trong event source có method thông báo sự kiện, khi có sự kiện xảy ra tại event source, event source sẽ thông báo cho event listener nhờ method này. Thông tin về sự kiện chứa trong Event object. Event object được truyền từ event source sang event listener. Event listener có chứa method để xử lý sự kiện.
MÔ HÌNH SỰ KIỆN MÔ HÌNH SỰ KIỆN
• Event listener phải đăng ký với event source thì mới có
thể nhận được các thông báo từ event source.
• Mỗi sự kiện trong Java có thể tương ứng với một hoặc
38
g n ũ D n ấ T õ V
:
V G
nhiều bộ lắng nghe sự kiện.
EVENT OBJECTS EVENT OBJECTS
• Event Object đóng gói tất cả các thông tin về sự kiện
mà nó đặc tả. Ví dụ, Event Object về sự kiện chuột sẽ chứa các thông tin như tọa độ của chuột, nút nào của chuột được nhấn và nhấn mấy lần.
39
g n ũ D n ấ T õ V
:
V G
• Lớp cơ sở java.util.EventObject có các phương thức theo bảng sau. Trong đó, phương thức toString() có thể đọc ra (read out) một Event Object như là một chuỗi.
EVENT OBJECTS EVENT OBJECTS
• Bất cứ khi nào ta muốn định nghĩa một event object để thông tin về một sự kiện nào đó thì ta phải tạo một subclass thừa kế từ java.util.EventObject và tên lớp phải có đuôi là “Event” để dễ quản lý.
public class SimpleEvent extends java.util.EventObject {
// construct the simple event type SimpleEvent(Object source) {
super(source);
}
}
40
g n ũ D n ấ T õ V
:
V G
• Ví dụ:
EVENT OBJECTS EVENT OBJECTS
Ví dụ: package BeansBook.Simulator; public class TempChangedEvent extends java.util.EventObject {
protected double theTemperature; // the new temperature value in Celsius // constructor public TempChangedEvent(Object source, double temperature) {
super(source); // pass the source object to the superclass theTemperature = temperature; // save the new temperature
} public double getTemperature() // get the temperature value {
return theTemperature;
}
}
41
g n ũ D n ấ T õ V
:
V G
EVENT LISTENERS EVENT LISTENERS
• Muốn tạo một bộ lắng nghe sự kiện ta phải định nghĩa một lớp con thừa kế từ interface java.util.EventListener
• Để dễ quản lý, tên của một bộ lắng nghe sự kiện phải
kết thúc bằng đuôi “Listener”.
• Trong bộ lắng nghe sự kiện phải có các hàm xử lý sự kiện. Bất cứ lớp nào muốn nhận thông báo về sự kiện đều phải hiện thực phương thức đó.
• Một bộ lắng nghe sự kiện có thể có nhiều method để xử lý sự kiện. Mỗi method tương ứng với một sự kiện khác nhau.
– void
42
g n ũ D n ấ T õ V
:
V G
• Các method đó theo design pattern sau đây:
EVENT LISTENERS EVENT LISTENERS
void tempChanged(TempChangedEvent evt);
} • Ví dụ: package BeansBook.Simulator; public interface AdvancedTempChangeListener extends TempChangeListener {
// this method is called if the temperature drops below the freezing // point of water void tempBelowFreezing(TempChangedEvent evt); // this method is called if the temperature rises above the boiling point of water void tempAboveBoiling(TempChangedEvent evt);
}
43
g n ũ D n ấ T õ V
:
V G
• Ví dụ: package BeansBook.Simulator; public interface TempChangeListener extends java.util.EventListener { // this method is called whenever the ambient temperature changes
EVENT SOURCES EVENT SOURCES
• Event Source là các đối tượng sinh ra sự kiện. Các đối
tượng này phải có các phương thức register và
unregister để cho phép các Event listener đăng ký.
– public void add
• Nhiều listener có thể đăng ký vào một event source. Khi đó, nếu một sự kiện xảy ra thì sẽ được thông báo đến nhiều listener cùng một lúc.
• Bản thân Event source phải có một hàm thông báo sự
Object newValue);
44
g n ũ D n ấ T õ V
:
V G
kiện. Ví dụ: – public void firePropertyChange(String propertyName, Object oldValue,
EVENT SOURCES EVENT SOURCES
Ví dụ: import java.util.Vector;
• public class Temperature {
currentTemp = startingTemp; }
// the current temperature in Celsius protected double currentTemp = 22.2; // the collection of objects listening for temperature changes private Vector tempChangeListeners = new Vector(); public Temperature(double startingTemp) // the constructors { public Temperature() { } // add a temperature change listener public synchronized void addTempChangeListener(TempChangeListener l) {
tempChangeListeners.addElement(l);
}
if (!tempChangeListeners.contains(l)) // add a listener if it is not already registered { // remove a temperature change listener
} public synchronized void removeTempChangeListener(TempChangeListener l) {
if (tempChangeListeners.contains(l)) // remove it if it is registered {
tempChangeListeners.removeElement(l);
}
} //còn tiếp ở slide sau
45
g n ũ D n ấ T õ V
:
V G
EVENT SOURCES EVENT SOURCES
// tiếp theo slide trước // notify listening objects of temperature changes protected void notifyTemperatureChange() {
// create the event object TempChangedEvent evt = new TempChangedEvent(this, currentTemp); // make a copy of the listener object vector so that it cannot // be changed while we are firing events Vector v; synchronized(this) { v = (Vector) tempChangeListeners.clone(); } // fire the event to all listeners int cnt = v.size(); for (int i = 0; i < cnt; i++) {
TempChangeListener client = (TempChangeListener)v.elementAt(i); client.tempChanged(evt);
}
}
}
46
g n ũ D n ấ T õ V
:
V G
EVENT SOURCES EVENT SOURCES
• Ví dụ: package BeansBook.Simulator; public class Thermometer implements TempChangeListener {
// a reference to the temperature object that we are monitoring protected Temperature theTemperature; Thermometer(Temperature temperature) {
theTemperature = temperature; // register for temperature change events theTemperature.addTempChangeListener(this);
} // handle the temperature change events public void tempChanged(TempChangedEvent evt) {
// do something with the temperature that we can retrieve // by calling evt.getTemperature()
}
47
}
g n ũ D n ấ T õ V
:
V G
EVENT ADAPTERS EVENT ADAPTERS
• Nếu một đối tượng muốn lắng nghe các sự kiện từ
nhiều nguồn khác nhau, nó sẽ phải hiện thực interface tương ứng với mỗi nguồn. Đây không phải là phương pháp hay nếu chỉ có một vài sự kiện là cần thiết cho listener.
• Hoặc khi một listener lắng nghe cùng một sự kiện từ nhiều nguồn khác nhau thì nó phải biết sự kiện được sinh ra từ nguồn nào.
• Để giải quyết các rắc rối trên, Java cho phép dùng
48
g n ũ D n ấ T õ V
:
V G
adapter. Adapter đóng vai trò trung gian giữa nguồn và đích của sự kiện.
EVENT ADAPTERS EVENT ADAPTERS
49
g n ũ D n ấ T õ V
:
V G
EVENT ADAPTERS EVENT ADAPTERS
• Các ví dụ trước ta đã xây dựng lớp Thermometer (nhiệt kế) để lắng nghe sự thay đổi nhiệt độ và nó xử lý sự kiện thay đổi nhiệt độ bằng phương thức tempChange(). Giả sử Thermometer lắng nghe sự thay đổi nhiệt độ từ hai event source là temperature1 và temperature2 (là instance của lớp Temperature). Nếu không dùng adapter thì ta phải viết code như sau: // handle changes to Temperature object 1 protected void temperature1Changed(double newTemp) { } // handle changes to Temperature object 2 protected void temperature2Changed(double newTemp) { }
Hoặc:
public void tempChanged(TempChangeEvent evt) {
if (temperature1 == evt.getSource()) { temperature1Changed(evt.getTemperature()); } else if (temperature2 == evt.getSource()) { temperature2Changed(evt.getTemperature()); }
}
50
g n ũ D n ấ T õ V
:
V G
EVENT ADAPTERS EVENT ADAPTERS
51
g n ũ D n ấ T õ V
:
V G
• Nếu dùng adapter chen giữa Thermometer và các Temperature thì ta sẽ xây dựng theo mô hình sau:
EVENT ADAPTERS EVENT ADAPTERS
// the constructor public TemperatureAdapter(Temperature t) {
// register for events t.addTempChangeListener(this);
// forward the event
} // handle the event public void tempChanged(TempChangedEvent evt) { }
} //xem tiếp ở slide tiếp theo
52
g n ũ D n ấ T õ V
:
V G
• Mỗi apdater tương ứng cho một Temperature, nghĩa là mỗi adapter nhận sự kiện thay đổi từ mỗi event source khác nhau. Có mối quan hệ 1-1 giữa event source và adapter. Có mối quan hệ 1-nhiều giữa event target và adapter. package BeansBook.Simulator; public class TemperatureAdapter implements TempChangeListener {
EVENT ADAPTERS EVENT ADAPTERS
•
Sau đó, ta xây dựng hai adapater tương ứng cho temperater1 và temperater2 như sau:
public class TemperatureAdapter1 extends TemperatureAdapter {
protected Thermometer target; // the constructor TemperatureAdapter1(Thermometer targ, Temperature t) {
// pass this to the superclass super(t); target = targ;
} public void tempChanged(TempChangedEvent evt) {
target.temperature1Changed(evt.getTemperature());
}
}
53
g n ũ D n ấ T õ V
:
V G
EVENT ADAPTERS EVENT ADAPTERS
•
Adapater cho temperater2 như sau:
public class TemperatureAdapter2 extends TemperatureAdapter {
protected Thermometer target; // the constructor TemperatureAdapter2(Thermometer targ, Temperature t) {
// pass this to the superclass super(t); target = targ;
} public void tempChanged(TempChangedEvent evt) {
target.temperature2Changed(evt.getTemperature());
}
}
54
g n ũ D n ấ T õ V
:
V G
SINGLE ADAPTERS SINGLE ADAPTERS
• Nhược điểm từ các ví dụ trên là số lượng adapter sẽ tăng lên khi có nhiều event source. Phương pháp single adapter cho phép ta tạo ra một adapter dùng chung cho các event source.
55
g n ũ D n ấ T õ V
:
V G
SINGLE ADAPTERS SINGLE ADAPTERS
•
Ta sẽ viết adapter mới như sau:
package BeansBook.Simulator; import java.lang.reflect.*; import java.util.*; public class GenericTemperatureAdapter implements TempChangeListener // the adapter receives the events {
protected Object theTarget; // the target object protected Class theTargetClass; // the class of the target object // the class array for the parameters used for the target method protected final static Class paramClasses[] =
{ BeansBook.Simulator.TempChangedEvent.class };
// the mapping of source objects to callback methods protected Hashtable mappingTable = new Hashtable(); // constructor public GenericTemperatureAdapter(Object target) {
theTarget = target; theTargetClass = target.getClass();
}
//còn tiếp ở slide kế tiếp
56
g n ũ D n ấ T õ V
:
V G
SINGLE ADAPTERS SINGLE ADAPTERS
// add an event source, along with the name of the method to call on the target when the event is received
public void registerEventHandler(Temperature tmp, String methodName)
{
throws NoSuchMethodException Method mthd = theTargetClass.getMethod(methodName, paramClasses); tmp.addTempChangeListener(this); mappingTable.put(tmp, mthd);
}
public void tempChanged(TempChangedEvent evt) // implement the listener method {
try {
// invoke the registered method on the target Method mthd = (Method)mappingTable.get(evt.getSource()); Object params[] = { evt }; mthd.invoke(theTarget, params);
} catch (IllegalAccessException e) { System.out.println(e); } catch (InvocationTargetException e) { System.out.println(e); }
}
}
57
g n ũ D n ấ T õ V
:
V G
SINGLE ADAPTERS SINGLE ADAPTERS
•
Lúc này ta phải viết lại event target (là lớp Thermometer) như sau:
package BeansBook.Simulator; public class Thermometer {
// references to the two temperature objects that we are monitoring protected Temperature theTemperature1; protected Temperature theTemperature2; // the temperature change adapter protected GenericTemperatureAdapter tempAdapter;
// constructor Thermometer(Temperature temperature1, Temperature temperature2) {
// save references to the temperature objects theTemperature1 = temperature1; theTemperature2 = temperature2;
// còn tiếp ở slide tiếp theo
58
g n ũ D n ấ T õ V
:
V G
SINGLE ADAPTERS SINGLE ADAPTERS
// create the adapter tempAdapter = new GenericTemperatureAdapter(this); try // register the handler methods { tempAdapter.registerEventHandler(theTemperature1,"temperature1Changed"); tempAdapter.registerEventHandler(theTemperature2,"temperature2Changed"); } catch (NoSuchMethodException e) { System.out.println(e); }
// handle changes to Temperature object 1 public void temperature1Changed(TempChangedEvent evt) { } // handle changes to Temperature object 2 public void temperature2Changed(TempChangedEvent evt); { }
59
}
g n ũ D n ấ T õ V
:
V G
PHẦN 5 PERSISTENCE (tính bảo tồn của Bean)
60
g n ũ D n ấ T õ V
:
V G
KHÁI NIỆM PERSISTENCE KHÁI NIỆM PERSISTENCE
• Persistence: một Bean phải có tính chất bảo tồn
(persistence). Đó là khả năng tự lưu trữ lại (save) thông tin các trạng thái (states), các thuộc tính (properties), các trường (fields) của một bean ra bộ nhớ ngoài và sau này khi cần thì dựa vào các thông tin đó để truy cập, phục hồi lại một bean.
• Serialization: quá trình tạo ra persistence trong Java được gọi là serialization. Động tác serialization một object là chuyển một object thành luồng dữ liệu (data stream) rồi lưu ra bộ nhớ ngoài.
61
g n ũ D n ấ T õ V
:
V G
• Deserialization: sau khi serialization, một container object muốn sử dụng bean thì tái xây dựng nó dựa theo data stream của bean đã được lưu trữ trước.
SERIALIZABLE CLASS SERIALIZABLE CLASS • Tất cả các bean mà ta tạo ra phải có tính persistence. Muốn vậy, các bean phải là lớp thừa kế từ interface java.io.Serializable hoặc java.io.Externalizable. Các interface này cho phép chúng ta lựa chọn automatic serialization hay customized serialization.
• Lớp con nào thừa kế từ một lớp có tính serialization
(serializable class) thì cũng có tính serialization. • Một số serializable class trong java là: Component,
String, Date, Vector, Hashtable (Applet là subclass của Component).
62
g n ũ D n ấ T õ V
:
• Một số non-serializable class là: Image, Thread,
V G
Socket và InputStream. Nếu ta cố tình serialize một non-serializable class thì sẽ sinh ra ngoại lệ NotSerializableException
SERIALIZABLE CLASS SERIALIZABLE CLASS
•
•
–
–
–
Automatic serialization: hiện thực bằng Serializable interface. The Java sẽ serialize toàn bộ một đối tượng một cách tự động (trừ các field có tiền tố transient và static) Customized serialization.: loại trừ ra các fields nào mà ta không muốn serializ bằng cách đánh dấu nó là the transient hoặc static. Customized file format: hiện thực bằng Externalizable interface với hai phương thức ghi và đọc một object.
63
g n ũ D n ấ T õ V
:
V G
Java Object Serialization API sẽ tự động lưu trữ các fields của một Serializble Object ra bộ nhớ ngoài bao gồm primitive types, arrays và strings. Một số field có tiền tố transient hoặc static thì không được lưu ra ngoài. Ta có thể chọn mức độ Serialize cho một bean theo 3 mức sau:
ỢC XML SSƠ Ơ LLƯƯỢC XML
Phần ngôn ngữ XML dành cho Java Bean có những tag sau đây: • Một XML preamble mở đầu cho biết version của XML và kiểu mã hóa
(encoding).
• Một
cần xây dựng lại một object từ dạng đã serialize của chính
• Ví dụ:
• Hoặc ví dụ:
64
g n ũ D n ấ T õ V
:
V G
ỢC XML SSƠ Ơ LLƯƯỢC XML
Các tag định nghĩa các kiểu thuộc tính nguyên tố (primitive type):
Ví dụ:
Một
Ví dụ:
Một
65
Ví dụ:
g n ũ D n ấ T õ V
:
V G
ỢC XML SSƠ Ơ LLƯƯỢC XML
• Đoạn mã sau đây là dạng lưu trữ XML được sinh ra từ một SimpleBean
66
g n ũ D n ấ T õ V
:
V G
Long term Persistence VíVí dụdụ Long term Persistence
• Giả sử ta muốn lưu một JFrame object vào một file để
có thể khôi phục lại sau này. Nếu ta nhìn vào mã nguồn (source code) của lớp JFrame và lớp cha của nó (superclasses), khi đó ta sẽ thấy hàng tá các fields. Nếu khi frame được serialize, giá trị của tất cả các field phải được lưu vào file. Trước hết, hãy nhìn vào cách frame được xây dựng sau đây:
67
g n ũ D n ấ T õ V
:
V G
JFrame frame = new JFrame(); frame.setTitle("My Application"); frame.setVisible(true);
Long term Persistence VíVí dụdụ Long term Persistence • Phương thức constructor ngầm định sẽ khởi động tất cả các fields, một số các properties được thiết lập . Sau đó, khi ta có frame object được rồi, thì cơ chế JavaBeans persistence sẽ lưu chính xác những phát biểu này đưới dạng XML như sau:
68
g n ũ D n ấ T õ V
:
V G
Long term Persistence VíVí dụdụ Long term Persistence
• Có một trở ngại nho nhỏ khi dùng phương pháp này.
Chẳng hạn, lời gọi: – frame.setSize(600, 400);
• không phải là một property setter, nhưng bộ mã hóa
XML (XMLEncoder) xử lý lệnh này bằng cách viết câu
lệnh sau:
69
g n ũ D n ấ T õ V
:
V G
Long term Persistence VíVí dụdụ Long term Persistence
• Để lưu một object thành luồng dữ liệu (data stream), ta
dùng XMLEncoder:
XMLEncoder out = new XMLEncoder(new
FileOutputStream(. . .));
out.writeObject(frame); out.close();
• Để đọc dữ liệu trở lại, ta dùng, XMLDecoder: XMLDecoder in = new XMLDecoder(new
FileInputStream(. . .));
JFrame newFrame =
(JFrame) in.readObject();
70
g n ũ D n ấ T õ V
:
V G
in.close();
PersistentFrameTest.java VíVí dụdụ: : PersistentFrameTest.java
• Chương trình sau đây trình diễn cách mà một frame nạp (load) và lưu (save) chính nó. Khi chạy chương trình, đầu tiên ta phải nhấp vào button Save để save frame vào file. Sau đó di chuyển frame ban đầu đến một vị trí khác rồi nhấp vào button Load để thấy một frame khác xuất hiện ở vị trí ban đầu. Nhớ nhìn vào bên trong file XML mà chương trình sinh ra.
71
g n ũ D n ấ T õ V
:
V G
PersistentFrameTest.java VíVí dụdụ: : PersistentFrameTest.java
import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.*; import javax.swing.*; public class PersistentFrameTest {
public static void main(String[] args) {
chooser = new JFileChooser(); chooser.setCurrentDirectory(new File(".")); PersistentFrameTest test = new PersistentFrameTest(); test.init();
} public void init() {
frame = new JFrame(); frame.setLayout(new FlowLayout()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("PersistentFrameTest"); frame.setSize(400, 200); JButton loadButton = new JButton("Load"); frame.add(loadButton); 30. loadButton.addActionListener(EventHandler.create(ActionListener.class, this,"load")); JButton saveButton = new JButton("Save"); frame.add(saveButton); saveButton.addActionListener(EventHandler.create(ActionListener.class, this,"save")); frame.setVisible(true);
}
72
g n ũ D n ấ T õ V
:
V G
PersistentFrameTest.java VíVí dụdụ: : PersistentFrameTest.java
public void load() {
// show file chooser dialog int r = chooser.showOpenDialog(null); // if file selected, open if(r == JFileChooser.APPROVE_OPTION) {
try {
File file = chooser.getSelectedFile(); XMLDecoder decoder =
new XMLDecoder(new FileInputStream(file)); JFrame newFrame = (JFrame) decoder.readObject(); decoder.close();
JOptionPane.showMessageDialog(null, e);
} catch (IOException e) { }
}
73
}
g n ũ D n ấ T õ V
:
V G
PersistentFrameTest.java VíVí dụdụ: : PersistentFrameTest.java
public void save() {
// show file chooser dialog int r = chooser.showSaveDialog(null); // if file selected, save if(r == JFileChooser.APPROVE_OPTION) {
try { File file = chooser.getSelectedFile();
XMLEncoder encoder = new XMLEncoder(new
FileOutputStream(file));
encoder.writeObject(frame); encoder.close(); } catch (IOException e) { JOptionPane.showMessageDialog(null, e); }
}
} private static JFileChooser chooser; private JFrame frame;
74
g n ũ D n ấ T õ V
}
:
V G
PHẦN 6 Property Editor & Customizers
75
g n ũ D n ấ T õ V
:
V G
Property Editor KháiKhái niệmniệm Property Editor
• Một khía cạnh rất quan trong của lập trình trực quan đó là nó cho phép ta hiệu chỉnh các thuộc tính và các hành vi của component mà không cần phải viết code để hiệu chỉnh.
• Hình thức phổ biến cho việc này đó là tạo ra một
property sheet để dùng cho việc thiết lập các giá trị thuộc tính cho component.
• Như vậy, bên cạnh việc viết code cho lớp chính của
một Bean, ta còn phải hiện thực giao diện PropertyEditor để xây dựng một bộ soạn thảo thuộc tính cho Bean (tức là tạo ra property sheet).
• Các thuộc tính như Color, String, Boolean,…(các basic
76
g n ũ D n ấ T õ V
:
V G
type) đã có các property editors ngầm định rồi.
CÁC BƯỚC XÂY DỰNG PROPERTY EDITORS CÁC BƯỚC XÂY DỰNG PROPERTY EDITORS
• Tiến trình xây dựng một property editor như sau: – Tạo một Bean Infor Class tương ứng với Bean. – Triển khai code cho method
getPropertyDescriptors.
– Phương thức này trả về một mảng các đối
tượng PropertyDescriptor objects. Ta phải xây dựng một đối tượng tương ứng với một property được trình bày trong property editor.
77
g n ũ D n ấ T õ V
:
V G
Chart Bean Example Chart Bean Example
• Hãy xem Example 8-4 (chapter 8). ChartBean.java trong sách Core Java™ 2 Volume II - Advanced Features, Seventh EditionBy Cay S. Horstmann, Gary Cornell.
– Color property: graphColor – String property: title – int property: titlePosition – double[] property: values – boolean property: inverse
78
g n ũ D n ấ T õ V
:
V G
• Chart Bean của example 8-4 có các thuộc tính sau:
ChartBeanBeanInfo.java ChartBeanBeanInfo.java
package com.horstmann.corejava; import java.beans.*; /*The bean info for the chart bean, specifying the property editors.*/ public class ChartBeanBeanInfo extends SimpleBeanInfo public PropertyDescriptor[] getPropertyDescriptors() { { try { PropertyDescriptor titlePositionDescriptor =
new PropertyDescriptor("titlePosition", ChartBean.class);
titlePositionDescriptor.setPropertyEditorClass(TitlePositionEditor.class); PropertyDescriptor inverseDescriptor = new PropertyDescriptor("inverse", ChartBean.class); inverseDescriptor.setPropertyEditorClass(InverseEditor.class); PropertyDescriptor valuesDescriptor= new PropertyDescriptor("values", ChartBean.class); valuesDescriptor.setPropertyEditorClass(DoubleArrayEditor.class); return new PropertyDescriptor[] { new PropertyDescriptor("title", ChartBean.class),
titlePositionDescriptor, valuesDescriptor, new PropertyDescriptor("graphColor", ChartBean.class), inverseDescriptor
};
} catch (IntrospectionException e){ e.printStackTrace(); return null;}
}
}
79
g n ũ D n ấ T õ V
:
V G
Property editor ViếtViết mộtmột Property editor
• Để viết một Property editor, ta cần hiện thực interface
PropertyEditor hoặc lớp PropertyEditorSupport. • Ví dụ, để bắt đầu viết editor cho thuộc tính vị trí của
// property editor class for title position
class TitlePositionEditor extends PropertyEditorSupport
{ . . . }
tiêu đề (title) của Chart Bean ta làm như sau:
• Property Editor có thể là một simple editor chỉnh sửa
80
g n ũ D n ấ T õ V
:
V G
thuộc tính bằng text, bằng một choice, bằng giao diện GUI. Property Editor có thể dùng để chỉnh sửa các thuộc tính đơn, thuộc tính mảng, vân… vân…
Simple property editor Simple property editor
– private static final int LEFT = 0; – private static final int CENTER = 1; – private static final int RIGHT = 2;
class TitlePositionEditor extends PropertyEditorSupport {
public String getAsText() {
int value = (Integer) getValue(); return options[value];
} public void setAsText(String s) {
Với đoạn code này, khi nhập vị trí mới cho title của Chart Bean thì ta phải nhập vào một trong 3 chuỗi: “Left”, “Center”, “Right”
for (int i = 0; i < options.length; i++) { if (options[i].equals(s)) { setValue(i); return; } }
} private String[] options = { "Left", "Center", "Right" };
}
81
g n ũ D n ấ T õ V
:
V G
• Simple property editor làm việc bằng các chuỗi văn bản thông qua hai hàm setAsText và getAsText. • Ví dụ: xét thuộc tính titlePosition của Chart Bean.
Simple property editor Simple property editor
82
g n ũ D n ấ T õ V
:
V G
• Nếu nhập “Left”,”Center”,“Right” bằng tay thì ta có thể nhập bị sai hoặc người dùng không biết nhập vào chuỗi gì. May mắn là lớp PropertyEditorSupport có hỗ trợ một phương thức đơn giản cho phép chọn các giá trị của thuộc tính theo dạng một Choice. Đó là phương thức getTags, nó trả về một mảng các chuỗi.
TitlePositionEditor.java TitlePositionEditor.java
package com.horstmann.corejava; import java.beans.*; /*A custom editor for the titlePosition property of the ChartBean. The editor lets the
user choose between Left, Center, and Right */
public class TitlePositionEditor extends PropertyEditorSupport { public String[] getTags() { return options; }
private String[] options = { "Left", "Center", "Right" }; public String getJavaInitializationString() { return "" + getValue(); } public String getAsText() {
int value = (Integer) getValue(); return options[value];
} public void setAsText(String s) {
if (options[i].equals(s)) {setValue(i);return;}
for (int i = 0; i < options.length; i++) { }
}
83
g n ũ D n ấ T õ V
}
:
V G
MộtMột sốsố cáchcách khác
Editor Property khác đđểể tạotạo Editor Property
• GUI-Based Property Editors • The custom editor dialog box for editing an array
(Xem trong Chapter 8 sách “Core Java™ 2 Volume II -
84
g n ũ D n ấ T õ V
:
V G
Advanced Features, Seventh Edition” By Cay S. Horstmann, Gary Cornell)
Customizers Customizers
• Bên cạnh việc Property Editor để chỉnh sửa giá trị của các property trong một Bean, chúng ta cũng có thể tạo ra Customizer editor để chỉnh sửa thuộc tính. Khi nhấp phải vào một Bean (lúc sử dụng Bean để thiết kế chương trình) thì Customizer sẽ xuất hiện.
• Xem thêm cách viết và ví dụ trong Chapter 8 sách “Core Java™ 2 Volume II - Advanced Features, Seventh Edition” By Cay S. Horstmann, Gary Cornell.
85
g n ũ D n ấ T õ V
:
V G
HẾT BÀI SỐ 1
86
g n ũ D n ấ T õ V
:
V G