3. Lựa chọn các lớp (1)
Mỗi lớp biểu diễn một khái niệm đơn trong
lĩnh vực của bài toán
Tên của lớp nên là 1 danh từ mô tả khái niệm
đó. VD:
Khái niệm trong toán học:
Điểm (Point)
Hình chữ nhật (Rectangle)
Hình elíp (Ellipse)
Khái niệm trong đời sống:
Tài khoản ngân hàng (BankAccount)
Quầy thu tiền (CashRegister)
2009-2010 OOP - http://mim.hus.edu.vn/elearning 3
4. Lựa chọn các lớp (2)
Nên phân biệt các loại lớp:
Loại lớp cho các đối tượng thực hiện 1 kiểu công
việc nào đó (vd: Scanner, Random)
Loại lớp tiện ích chỉ chứa các phương thức tĩnh và
các hằng (vd: Math)
Lớp khởi động chương trình: chỉ chứa hàm main
Nguyên tắc số 1 khi xác định tên cho các lớp:
tìm các danh từ trong mô tả bài toán
2009-2010 OOP - http://mim.hus.edu.vn/elearning 4
5. Tính gắn kết (1)
Mỗi lớp nên biểu diễn một khái niệm đơn
Giao diện công khai của 1 lớp là nhất quán nếu tất cả
các đặc trưng của nó đều gắn kết với khái niệm mà lớp
đó biểu diễn
Chẳng hạn lớp CashRegister (BigJava – ch04) thiếu tính
gắn kết
public class CashRegister {
public void enterPayment(int dollars, int quarters,
int dimes, int nickels, int pennies)
...
public static final double NICKEL_VALUE = 0.05;
public static final double DIME_VALUE = 0.1;
public static final double QUARTER_VALUE = 0.25;
...
}
2009-2010 OOP - http://mim.hus.edu.vn/elearning 5
6. Tính gắn kết (2)
Thực tế, lớp CashRegister như trên đề cập tới 2 khái niệm:
quầy thu ngân và tiền xu
Giải pháp: tạo 2 lớp
public class Coin {
public Coin(double aValue, String aName){ ... }
public double getValue(){ ... }
...
}
public class CashRegister {
public void enterPayment(int coinCount, Coin coinType)
{ ... }
...
}
2009-2010 OOP - http://mim.hus.edu.vn/elearning 6
7. Tính móc nối (1)
1 lớp phụ thuộc vào 1 lớp khác nếu nó sử dụng các
đối tượng của lớp đó
Lớp CashRegister phụ thuộc vào lớp Coin để xác định số
tiền trả
Lớp Coin không phụ thuộc vào lớp CashRegister
Tính móc nối cao: nhiều phụ thuộc giữa các lớp
Cần giảm thiểu sự móc nối để hạn chế ảnh hưởng
khi có thay đổi về giao diện của mỗi lớp
Vẽ sơ đồ lớp để hiển thị quan hệ giữa các lớp
Sử dụng UML (Unified Modeling Language): kí hiệu
dùng cho phân tích, thiết kế hướng đối tượng
2009-2010 OOP - http://mim.hus.edu.vn/elearning 7
8. Tính móc nối (2)
Quan hệ phụ thuộc
giữa 2 lớp
CashRegister và
Coin
2009-2010 OOP - http://mim.hus.edu.vn/elearning 8
9. Tính móc nối cao/thấp
2009-2010 OOP - http://mim.hus.edu.vn/elearning 9
10. Các lớp không biến đổi
(immutable classes)
Các lớp không biến đổi là các lớp không có
phương thức biến đổi (mutator) thuộc tính
đối tượng
VD: String, Double, v.v.
String name = "John Q. Public";
String uppercased =
name.toUpperCase(); // name is not
changed
Việc xuất ra tham chiếu tới một đối tượng
thuộc các lớp này là an toàn, các chương
trình khác không thể biến đổi được trạng thái
đối tượng đó
2009-2010 OOP - http://mim.hus.edu.vn/elearning 10
11. Hiệu ứng phụ (1)
Hiệu ứng phụ của 1 phương thức: biến đổi dữ
liệu bên ngoài
public void transfer(double amount,
BankAccount other) {
balance = balance - amount;
other.balance = other.balance + amount;
// Modifies explicit parameter
}
Biến đổi tham biến hiện có thể dẫn đến hiệu
ứng ngoài tầm kiểm soát của người lập trình
=> nếu có thể thì nên tránh
2009-2010 OOP - http://mim.hus.edu.vn/elearning 11
12. Hiệu ứng phụ (2)
Ví dụ khác: đầu ra của chương trình
public void printBalance() // Not recommended
{
System.out.println("The balance is now $" + balance);
}
Ý tưởng không tốt: Thông báo bằng tiếng Anh, dòng dữ
liệu ra là System.out
Tốt nhất là tách biệt được việc nhập/xuất dữ liệu với mục
đích chính của lớp cần xây dựng
2009-2010 OOP - http://mim.hus.edu.vn/elearning 12
13. Truyền tham biến
Các phương thức truyền tham biến: theo giá trị (value)/theo
địa chỉ (reference)
Java: truyền theo giá trị
Một phương thức có thể thay đổi trạng thái của đối tượng làm tham
biến, nhưng không thay được địa chỉ của đối tượng đó
public class BankAccount {
public void transfer(double amount, BankAccount otherAccount)
{
balance = balance - amount;
double newBalance = otherAccount.balance + amount;
otherAccount = new BankAccount(newBalance);
// Won't work
}
}
VD: harrysChecking.transfer(500, savingsAccount);
2009-2010 OOP - http://mim.hus.edu.vn/elearning 13
14.
15. Điều kiện trước (1)
Điều kiện trước (precondition): Yêu cầu mà chương
trình gọi phương thức phải tuân theo
Công bố điều kiện trước trong tài liệu hướng dẫn
/**
Deposits money into this account.
@param amount the amount of money to deposit
(Precondition: amount >= 0)
*/
Nếu điều kiện trước bị vi phạm, phương thức không
chịu trách nhiệm về việc tính đúng kết quả mà có thể
xử lí theo cách bất kì
2009-2010 OOP - http://mim.hus.edu.vn/elearning 15
16. Điều kiện trước (2)
Nếu điều kiện trước bị vi phạm, phương thức
có thể “ném” ngoại lệ (throw exception) – bài
12
if (amount < 0) throw new IllegalArgumentException();
balance = balance + amount;
Phương thức không bắt buộc phải kiểm tra
điều kiện trước, chương trình gọi phải chịu
trách nhiệm nếu không tuân thủ điều kiện đã
đưa ra
2009-2010 OOP - http://mim.hus.edu.vn/elearning 16
17. Điều kiện trước (3)
Phương thức có thể thực hiện kiểm tra xác nhận
bằng chỉ thị assert
Cú pháp: assert condition;
VD: assert amount >= 0;
Bật chế độ kiểm tra xác nhận khi chạy:
java –enableassertions ClassName
Nếu biểu thức điều kiện có giá trị false, chương trình sẽ ném
ngoại lệ
Tránh việc lẳng lặng kết thúc phương thức khi điều
kiện trước không thoả mãn:
if (amount < 0) return; // Not recommended; hard to debug
balance = balance + amount;
2009-2010 OOP - http://mim.hus.edu.vn/elearning 17
18. Điều kiện sau
Điều kiện sau (postcondition): điều kiện thoả mãn
sau khi thực hiện phương thức
Nếu lời gọi phương thức thoả mãn điều kiện trước thì
cũng phải đảm bảo thoả mãn điều kiện sau
Có 2 loại điều kiện sau:
Giá trị trả lại được tính toán đúng
Đối tượng ở trạng thái xác định nào đó khi thực hiện xong
phương thức
/**
Deposits money into this account.
(Postcondition: getBalance() >= 0)
@param amount the amount of money to deposit
(Precondition: amount >= 0)
*/
2009-2010 OOP - http://mim.hus.edu.vn/elearning 18
19. Phương thức tĩnh - Trường dữ
liệu tĩnh
Phương thức tĩnh:
Mỗi phương thức phải thuộc 1 lớp nào đó
Phương thức tĩnh: Không có tham biến ẩn
phương thức dùng cho các tính toán không áp dụng lên đối tượng
của lớp
Trường dữ liệu tĩnh
Trường dữ liệu chung cho tất cả các đối tượng trong lớp
Chú ý khởi tạo trường dữ liệu tĩnh
public class BankAccount{
. . .
private static int lastAssignedNumber = 1000;
//Executed once, when class is loaded
}
Trừ trường hợp dữ liệu là hằng (final), các trường dữ liệu tĩnh nên
có quyền truy nhập private
2009-2010 OOP - http://mim.hus.edu.vn/elearning 19
20. Tổ chức các lớp liên quan
thành các gói
Gói (package): Tập các lớp có liên quan
Để đặt các lớp trong 1 tệp vào 1 gói, dòng
đầu tiên trong tệp mã nguồn cần có chỉ thị:
package packageName;
Tên của gói chứa 1 hay nhiều tên phân cách
nhau bằng dấu chấm (.)
VD: package com.horstmann.bigjava;
Gói ngầm định (default package) không có
tên
2009-2010 OOP - http://mim.hus.edu.vn/elearning 20
21. Khai báo sử dụng gói (import)
Có thể sử dụng 1 lớp thuộc 1 gói mà không
cần lệnh import
Trong toàn bộ chương trình phải viết tên đầy đủ
của lớp đó
java.util.Scanner in = new
java.util.Scanner(System.in);
Để không phải khai báo nhiều lần cho các lớp
trong cùng 1 gói, dùng kí tự gộp *
import java.util.*;
2009-2010 OOP - http://mim.hus.edu.vn/elearning 21
22. Tên gói và định vị các lớp
Dùng gói để tránh xung đột tên lớp
VD: java.util.Timer và javax.swing.Timer
Tên gói không được nhập nhằng
Khuyến cáo: Bắt đầu tên gói với tên miền Internet
(com.horstmann.bigjava)
Tên đường dẫn của các lớp trong gói:
phải đúng với tên gói (com/horstman/bigjava)
được bắt đầu với đường dẫn trong biến môi trường
CLASSPATH
chứa danh sách các thư mục cơ sở có thể chứa các thư mục
của các gói
set CLASSPATH=c:homewalters;.
2009-2010 OOP - http://mim.hus.edu.vn/elearning 22
23. Thư mục cơ sở và thư mục
con cho các gói
2009-2010 OOP - http://mim.hus.edu.vn/elearning 23