Cách dùng Lớp và Phương thức "Abstract" trong Java
Trừu tượng hóa (Abstraction) là một trong ba nguyên lý cốt lõi lập trình hướng đối tượng – bên cạnh đóng gói (encapsulation) và kế thừa (inheritance).
Trừu tượng hóa là cách giảm độ phức tạp chương trình và làm mã dễ đọc hơn. Trong Java, trừu tượng hóa cho phép:
- chỉ hiển thị chi tiết nhất định của lớp và
- giấu tất cả chi tiết khác của lớp đó.
Trừu tượng hóa áp dụng cho cả lớp và phương thức trong Java.
Hướng dẫn này thảo luận cơ bản trừu tượng hóa Java, cách dùng lớp trừu tượng, và cách dùng phương thức trừu tượng. Chúng ta cũng đi qua vài ví dụ giúp hiểu rõ khái niệm quan trọng này.
Trừu tượng hóa Java (Java Abstraction)
Lập trình hướng đối tượng là loại lập trình dùng đối tượng và lớp biểu diễn dữ liệu và phương thức. Dùng đối tượng và lớp giảm lặp lại mã và làm chương trình hiệu quả hơn.
Java là ngôn ngữ lập trình hướng đối tượng. Vì vậy, bao gồm nhiều tính năng làm việc đối tượng và lớp. Trừu tượng hóa là một tính năng đó. Trừu tượng hóa cho phép chỉ hiển thị thông tin nhất định cho lớp trong Java.
Có hai trường hợp trừu tượng hóa dùng trong Java: trong lớp và trong phương thức.
Lớp trừu tượng Java (Java Abstract Classes)
Trong Java, lớp trừu tượng là lớp không thể tạo đối tượng nào từ đó. Nói cách khác, lớp trừu tượng không thể khởi tạo (instantiated).
Để tạo lớp trừu tượng trong Java, dùng từ khóa abstract. Ví dụ lớp trừu tượng Java:
abstract class BankAccount { // Code here } Vì là lớp trừu tượng, nếu thử tạo đối tượng với lớp này, chương trình trả về lỗi.
Ví dụ, giả sử thử tạo thể hiện lớp BankAccount. Muốn gọi thể hiện lucyAccount, lưu thông tin ngân hàng Lucy. Lucy là khách hàng. Dùng mã sau thử tạo thể hiện:
BankAccount lucyAccount = new BankAccount();
Khi chạy mã, chương trình trả về:
BankAccount is abstract; cannot be instantiated
Như thấy, không thể gán lớp trừu tượng cho đối tượng.
Tuy nhiên, vẫn có thể tạo lớp con (subclass) từ lớp trừu tượng. Phần sau thảo luận cách tạo lớp con từ lớp trừu tượng.
Kế thừa lớp trừu tượng (Abstract Class Inheritance)
Như đã nói, không gán đối tượng lớp trừu tượng. Vì vậy, để truy cập nội dung lớp trừu tượng – tức thuộc tính và phương thức liên kết – phải kế thừa (inherit) lớp.
Giả sử tạo chương trình lưu thông tin tài khoản ngân hàng. Chương trình bao gồm hai lớp: BankAccount và CheckingAccount. BankAccount là lớp cha (parent) lưu thuộc tính và phương thức làm việc tài khoản. CheckingAccount là lớp con (child) kế thừa phương thức.
Ví dụ này, BankAccount là lớp trừu tượng. Chỉ muốn dùng tạo tài khoản thanh toán (checking).
Mã dùng làm việc BankAccount và CheckingAccount:
abstract class BankAccount { public void viewAccountNumber() { System.out.println("Account number: #1932042"); } } class CheckingAccount extends BankAccount { } class Main { public static void main(String[] args) { CheckingAccount lucyAccount = new CheckingAccount(); lucyAccount.viewAccountNumber(); } } Mã trả về:
Account number: #1932042
Trong ví dụ, tạo ba lớp:
- BankAccount. Lớp trừu tượng. Chứa phương thức
viewAccountNumber(). Vì trừu tượng, không tạo đối tượng lớp. - CheckingAccount. Lớp con. Với tư cách lớp con, kế thừa thuộc tính và phương thức BankAccount.
- Main. Lớp chứa mã chương trình chính.
Trong chương trình chính, tạo thể hiện CheckingAccount gọi lucyAccount. lucyAccount là đối tượng. Sau tạo ba lớp, dùng đối tượng lucyAccount trong phương thức viewAccountNumber().
Bảng sau tóm tắt phần quan trọng ví dụ:
| TÊN | LOẠI | MÔ TẢ |
| BankAccount | lớp trừu tượng/cha | Lưu thuộc tính và phương thức làm việc tài khoản. |
| CheckingAccount | lớp con | Kế thừa phương thức lớp cha. |
| Main | lớp | Chứa mã chương trình chính. |
| lucyAccount | đối tượng | Ứng dụng thực tế chương trình. |
Nếu quan tâm tìm hiểu thêm kế thừa Java, đọc hướng dẫn hoàn chỉnh tại đây.
Phương thức trừu tượng Java (Java Abstract Methods)
Ngoài lớp, phương thức cũng có thể trừu tượng.
Khi khai báo phương thức trừu tượng, dùng từ khóa abstract như trên. Không chỉ định nội dung, và chỉ khai báo phương thức trừu tượng trong lớp trừu tượng.
Ví dụ phương thức trừu tượng Java:
abstract void checkBalance();
Trong ví dụ, tạo phương thức trừu tượng checkBalance(). Phương thức không có thân (body) – nghĩa là không mã liên kết phương thức.
Quay lại ví dụ ngân hàng trước. Chương trình chứa phương thức trừu tượng: lucyAccount.viewAccountNumber();.
Dùng phương thức trừu tượng cho phép chương trình hiển thị số tài khoản khách hàng. Trong ví dụ trên (phần trước), lớp cha BankAccount đóng vai trò mẫu (template) cho lớp con.
Trong trường hợp này, lớp con là loại tài khoản ngân hàng khác nhau. Điều này vì khách hàng có thể nhiều loại tài khoản, và muốn thực hiện cùng hàm trên mỗi loại. Lớp con tạo trước: CheckingAccount.
Hãy quay lại khách hàng ví dụ. Lucy có tài khoản thanh toán, nhưng cũng có thể tài khoản tiết kiệm (savings) và tài khoản chứng khoán (brokerage). Muốn hiển thị số tài khoản cho ba loại. Làm được bằng tạo lớp con hai loại tài khoản thêm. Gọi: SavingsAccount, BrokerageAccount.
Vì đã tạo lớp cha BankAccount, có thể hiệu quả và tối thiểu lặp mã hiển thị số tài khoản ba loại.
Trong mã dưới, dùng từ khóa abstract hai lần. Đầu, khai báo lớp trừu tượng (BankAccount). Sau, khai báo phương thức trừu tượng sau giúp chương trình hiển thị số tài khoản khách hàng. Khai báo phương thức trừu tượng: abstract void viewAccountNumber();. Sau khởi tạo viewAccountNumber() trên lớp con CheckingAccount. Mã:
abstract class BankAccount { abstract void viewAccountNumber(); } class CheckingAccount extends BankAccount { public void viewAccountNumber() { System.out.println("Checking account number: #1932042"); } } class Main { public static void main(String[] args) { CheckingAccount lucyAccount = new CheckingAccount(); lucyAccount.viewAccountNumber(); } } Mã trả về:
Checking account number: #1932042
Ví dụ này trả về cùng đầu ra ví dụ trước, nhưng có vài khác biệt mã cần lưu ý. Chúng là:
- Khai báo phương thức trừu tượng. Ví dụ này, khai báo lớp trừu tượng BankAccount. Lớp chứa phương thức trừu tượng
viewAccountNumber(). - Mở rộng phương thức trừu tượng. Mở rộng BankAccount qua CheckingAccount. CheckingAccount kế thừa giá trị lưu trong phương thức BankAccount.
Trong CheckingAccount, định nghĩa phương thức – viewAccountNumber() – chỉ truy cập đối tượng CheckingAccount. Sau, để xem số tài khoản khách hàng, tạo đối tượng CheckingAccount.
Ví dụ Trừu tượng hóa Java (Java Abstraction Example)
Giờ đã thảo luận cả lớp trừu tượng và phương thức trừu tượng, khám phá ví dụ đầy đủ trừu tượng hóa Java. Để làm vậy, gộp mọi thứ thảo luận trong ví dụ ngân hàng trên.
Giả sử vận hành ngân hàng cung cấp hai loại tài khoản: thanh toán (checking) và tiết kiệm (savings). Quyết định viết chương trình cho chủ tài khoản kiểm tra số tài khoản.
Tại ngân hàng, nếu tài khoản là thanh toán, số tài khoản bắt đầu bằng ID khách hàng và kết thúc 555. Nếu tiết kiệm, số tài khoản kết thúc 777.
Chúng ta dùng mã sau tạo chương trình:
abstract class BankAccount { abstract void viewAccountNumber(); } class CheckingAccount extends BankAccount { public void viewAccountNumber() { System.out.println("Checking account number: #1932042555"); } } class SavingsAccount extends BankAccount { public void viewAccountNumber() { System.out.println("Savings account number: #1932042777"); } } class Main { public static void main(String[] args) { CheckingAccount ellieCheckingAccount = new CheckingAccount(); ellieCheckingAccount.viewAccountNumber() SavingsAccount ellieSavingsAccount = new SavingsAccount(); ellieSavingsAccount.viewAccountNumber(); } } Mã trả về:
Checking account number: #1932042555 Savings account number: #1932042777
Trong ví dụ, tạo lớp BankAccount. Lớp có một phương thức trừu tượng, viewAccountNumber().
Mỗi loại tài khoản gán số khác nhau, nên không thể thực thi viewAccountNumber() trong BankAccount. Thay vào đó, mỗi lớp con BankAccount thực thi viewAccountNumber().
Trong ví dụ, CheckingAccount gán số tài khoản là số bắt đầu ID khách hàng kết thúc 555. SavingsAccount gán số tài khoản bắt đầu ID khách hàng kết thúc 777.
Trong mã, khởi tạo thể hiện CheckingAccount cho khách hàng Ellie. Thể hiện tên ellieCheckingAccount, gọi viewAccountNumber() xem số tài khoản. Trả về:
Checking account number: #1932042555
Cũng khởi tạo thể hiện SavingsAccount, tên ellieSavingsAccount, gọi viewAccountNumber() xem số tài khoản. Trả về:
Savings account number: #1932042777
Kết luận
Trừu tượng hóa (Abstraction) là tính năng quan trọng lập trình hướng đối tượng. Cho phép giấu chi tiết lớp hoặc phương thức và chỉ hiển thị thông tin thiết yếu. Để tạo lớp và phương thức trừu tượng Java, dùng từ khóa abstract.
Hướng dẫn thảo luận, với ví dụ, cách trừu tượng hóa hoạt động, tại sao hữu ích, và cách tạo phương thức và lớp trừu tượng Java. Bây giờ bạn sẵn sàng làm việc lớp và phương thức trừu tượng Java như lập trình viên chuyên nghiệp!