oop 8
DESCRIPTION
slide java o lopTRANSCRIPT
Bài 8: Giao diện và tính đa hình
Giảng viên: Nguyễn Thị Minh Huyề[email protected]
Đỗ Thanh Hà[email protected]
2009-2010 OOP - http://mim.hus.edu.vn/elearning 2
Tài liệu tham khảo BigJava – chương 11
2009-2010 OOP - http://mim.hus.edu.vn/elearning 3
Tái sử dụng mã chương trình (1)
Xét ví dụ DataSet.java (ch07/input) Tìm giá trị trung bình và giá trị lớn nhất
của 1 tập các giá trị số Phải làm gì nếu muốn tìm trị trung bình và lớn
nhất của 1 tập các tài khoản ngân hàng (BankAccount, ch08)?
Hay muốn tìm loại tiền xu có giá trị cao nhất trong 1 tập các loại tiền xu (Coin, bài 6)?
2009-2010 OOP - http://mim.hus.edu.vn/elearning 4
Tái sử dụng mã chương trình (2)
public class DataSet // Modified for BankAccount objects { . . .
public void add(BankAccount x) { sum = sum + x.getBalance(); if (count == 0 || maximum.getBalance() < x.getBalance())
maximum = x; count++;
} public BankAccount getMaximum() {
return maximum; } private double sum; private BankAccount maximum; private int count;
}
2009-2010 OOP - http://mim.hus.edu.vn/elearning 5
Tái sử dụng mã chương trình (3)
public class DataSet // Modified for Coin objects { . . .
public void add(Coin x) { sum = sum + x.getValue(); if (count == 0 || maximum.getValue() < x.getValue())
maximum = x; count++;
} public Coin getMaximum() {
return maximum; } private double sum; private Coin maximum; private int count;
}
2009-2010 OOP - http://mim.hus.edu.vn/elearning 6
Tái sử dụng mã chương trình (4)
Các ví dụ trên có chung cơ chế phân tích dữ liệu, chỉ khác nhau về độ đo dữ liệu Các lớp liên quan có thể thống nhất 1 phương thức getMeasure
để thu được giá trị đo dùng trong quá trình phân tích Khi đó có thể cài 1 lớp duy nhất DataSet có thể sử dụng chung,
trong đó phần thân của phương thức add có dạng:
sum = sum + x.getMeasure(); if (count == 0 || maximum.getMeasure() < x.getMeasure())
maximum = x; count++;
Kiểu của biến x là gì? x cần phải tham chiếu tới bất kì lớp nào có hàm getMeasure.
2009-2010 OOP - http://mim.hus.edu.vn/elearning 7
Tái sử dụng mã chương trình (5) Để mô tả các lớp có chung một số thao tác nào đó
(như getMeasure), trong Java người ta khai báo một kiểu giao diện (interface) đặc tả các thao tác chung đó public interface Measurable {
double getMeasure();}
Khai báo interface liệt kê danh sách các nguyên mẫu phương thức (prototype) mà kiểu giao diện cần có
Các lớp có chung giao diện này sẽ cài đặt (implements) cụ thể các phương thức đặc tả trong kiểu giao diện.
2009-2010 OOP - http://mim.hus.edu.vn/elearning 8
Lớp DataSet dùng chung cho các đối tượng đo được
public class DataSet { . . .
public void add(Measurable x) { sum = sum + x.getMeasure(); if (count == 0 || maximum.getMeasure() < x.getMeasure())
maximum = x; count++;
} public Measurable getMaximum() {
return maximum; } private double sum; private Measurable maximum; private int count;
}
2009-2010 OOP - http://mim.hus.edu.vn/elearning 9
Cài đặt một kiểu giao diện Để khai báo 1 lớp cài đặt 1 kiểu giao diện, dùng
từ khoá implements public class BankAccount implements Measurable {
public double getMeasure() { return balance;
} // Additional methods and fields
} 1 lớp có thể cài đặt nhiều kiểu giao diện
Khi cài đặt 1 kiểu giao diện, lớp đó phải định nghĩa tất cả các phương thức đã đặc tả trong kiểu giao diện
2009-2010 OOP - http://mim.hus.edu.vn/elearning 10
Cú pháp Định nghĩa 1 kiểu giao diện
public interface InterfaceName { // method signatures
} Tất cả các phương thức trong kiểu giao diện đều
đương nhiên là public Cài đặt 1 kiểu giao diện
public class ClassName implements InterfaceName, InterfaceName, ... {
// interface method implementations // other methods // instance variables
} VD: Xem các lớp trong ch11/measure1
2009-2010 OOP - http://mim.hus.edu.vn/elearning 11
Sơ đồ UML (1) Sử dụng kiểu giao diện có thể giúp giảm tính
móc nối giữa các lớp Kí hiệu UML:
Kiểu giao diện được đánh dấu bằng nhãn «interface»
Mũi tên nét đứt với mũi hình tam giác kí hiệu quan hệ “is-a” giữa 1 lớp và 1 giao diện
Mũi tên nét đứt với mũi hình chữ v mở kí hiệu quan hệ “uses” hay quan hệ phụ thuộc
2009-2010 OOP - http://mim.hus.edu.vn/elearning 12
Sơ đồ UML (2)
VD
2009-2010 OOP - http://mim.hus.edu.vn/elearning 13
Chuyển đổi kiểu giữa lớp và giao diện
Có thể chuyển 1 kiểu lớp về 1 kiểu giao diện, với điều kiện lớp cài đặt giao diện BankAccount account = new BankAccount(10000);
Measurable x = account; // OK Ngược lại, để chuyển 1 kiểu giao diện về 1 kiểu lớp phải
thực hiện ép kiểu DataSet coinData = new DataSet();
coinData.add(new Coin(0.25, "quarter"));coinData.add(new Coin(0.1, "dime"));. . .// Get the largest coin Measurable max = coinData.getMaximum(); String name = max.getName(); // ERRORCoin maxCoin = (Coin) max;String name = maxCoin.getName();
2009-2010 OOP - http://mim.hus.edu.vn/elearning 14
Tính đa hình Biến kiểu giao diện dùng để chứa tham chiếu tới đối
tượng của 1 lớp cài đặt giao diện đó Measurable x;x = new BankAccount(10000);x = new Coin(0.1, "dime");
Có thể gọi bất kì phương thức nào của kiểu giao diện với tham biến ẩn x Tuỳ theo x đang tham chiếu tới đối tượng thuộc lớp nào thì áp
dụng phương thức cài đặt trong lớp đó => tính đa hình Gọi là liên kết muộn (late binding): khi chạy chương trình mới xác
định dùng phương thức của lớp nào Khác với liên kết sớm (early binding): chương trình dịch xác định
dùng phương thức nào trong các phương thức cùng tên
2009-2010 OOP - http://mim.hus.edu.vn/elearning 15
Sử dụng kiểu giao diện cho gọi lại (callback)
Nhược điểm của kiểu giao diện Measurable: Chỉ dùng được giao diện này để đo trong các lớp thuộc quyền của
người lập trình Chỉ đo/đánh giá được đối tượng theo 1 tiêu chí
VD với 1 tài khoản tiết kiệm không thể vừa đo theo số tiền trong tài khoản, vừa đo theo lãi suất
Cơ chế gọi lại (callback): cho phép 1 lớp gọi tới 1 phương thức đặc trưng tuỳ theo thông tin cần khai thác
Xét lớp DataSet Trong VD trước, việc đo 1 đối tượng do 1 phương thức của đối
tượng đó đảm nhiệm Thay cho cách làm đó, dùng 1 phương thức đo có tham biến hiện
là đối tượng cần đo
2009-2010 OOP - http://mim.hus.edu.vn/elearning 16
Sử dụng kiểu giao diện cho gọi lại (2)
Muốn vậy: Định nghĩa kiểu giao diệnpublic interface Measurer {
double measure(Object anObject); } Định nghĩa phương thức add trong DataSetpublic void add(Object x) {
sum = sum + measurer.measure(x); if (count == 0 || measurer.measure(maximum)
< measurer.measure(x)) maximum = x; count++;
}
2009-2010 OOP - http://mim.hus.edu.vn/elearning 17
Sử dụng kiểu giao diện cho gọi lại (3)
Cài đặt giao diện Measurer:public class RectangleMeasurer implements Measurer {
public double measure(Object anObject) {Rectangle aRectangle = (Rectangle) anObject;
double area = aRectangle.getWidth()*aRectangle.getHeight();
return area; }
} Sử dụng DataSet:
Measurer m = new RectangleMeasurer();DataSet data = new DataSet(m);data.add(new Rectangle(5, 10, 20, 30));data.add(new Rectangle(10, 20, 30, 40));. . .
2009-2010 OOP - http://mim.hus.edu.vn/elearning 18
Sơ đồ UML
Xem chương trình ch11/measure2
2009-2010 OOP - http://mim.hus.edu.vn/elearning 19
Lớp trong (inner classes) Có thể định nghĩa 1 lớp đơn giản bên trong 1 phương thức
Lớp này chỉ dùng được trong phương thức VD (ch11/measure3)
public class DataSetTester3 { public static void main(String[] args) {
class RectangleMeasurer implements Measurer { . . .
} Measurer m = new RectangleMeasurer();
DataSet data = new DataSet(m); . . .
} }
Chương trình dịch sẽ tạo ra 1 tệp riêng cho lớp trong DataSetTester3$1RectangleMeasurer.class
Nếu 1 lớp được định nghĩa trong 1 lớp khác nhưng ngoài các phương thức của lớp đó thì có thể dùng được lớp đó trong mọi phương thức của lớp ấy.
2009-2010 OOP - http://mim.hus.edu.vn/elearning 20
Ví dụ minh hoạ: Xử lí sự kiện đếm thời gian
javax.swing.Timer sinh các sự kiện đếm thời gian cách đều nhau, hữu dụng khi cần cập nhật 1 đối tượng trong 1 khoảng thời gian đều đặn
Cách dùng (Xem ch11/timer1): Định nghĩa 1 lớp MyListener cài đặt kiểu giao diện ActionListener: gửi sự kiện
tới bộ nghe public interface ActionListener { void actionPerformed(ActionEvent event);}
class MyListener implements ActionListener { void actionPerformed(ActionEvent event){ // This action will be executed at each timer event Place listener action here }}
Tạo đối tượng Timer với bộ nghe đã cài đặt MyListener listener = new MyListener();Timer t = new Timer(interval, listener);t.start();
2009-2010 OOP - http://mim.hus.edu.vn/elearning 21
Truy cập các biến xung quanh (1)
Các phương thức của 1 lớp trong có thể truy cập các biến định nghĩa trong phạm vi xung quanh Hữu dụng khi cài đặt các bộ điều khiển sự kiện VD: Làm hình động – di chuyển 1 hình 10 lần trong 1s
class Mover implements ActionListener { public void actionPerformed(ActionEvent event) {
// Move the rectangle }
} ActionListener listener = new Mover(); final int DELAY = 100; // Milliseconds between timer ticks Timer t = new Timer(DELAY, listener); t.start();
2009-2010 OOP - http://mim.hus.edu.vn/elearning 22
Truy cập các biến xung quanh (2)
Phương thức actionPerformed có thể truy cập các biến trong phạm vi xung quanh (ch11/timer2):
public static void main(String[] args) { . . . final Rectangle box = new Rectangle(5, 10, 20, 30); class Mover implements ActionListener {
public void actionPerformed(ActionEvent event) { // Move the rectangle box.translate(1, 1);
} } . . .
} Các biến địa phương muốn truy cập được bởi lớp trong phải được khai
báo là final Lớp trong có thể truy cập trường dữ liệu của đối tượng thuộc lớp ngoài 1 đối tượng thuộc lớp trong được tạo trong 1 phương thức tĩnh chỉ có
thể truy cập các trường dữ liệu tĩnh