Java: Trừu tượng (Abstract)

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Trong khi thực hiện thừa kế, ta hoàn toàn có thể tạo đối tượng của lớp cha cũng như lớp con. Tuy nhiên, điều gì sẽ xảy ra nếu người dùng muốn hạn chế sử dụng trực tiếp lớp cha? Đó là, trong một số trường hợp, ta có thể muốn định nghĩa một lớp cha trong đó chỉ khai báo cấu trúc của thực thể đã cho mà không đưa ra sự thực thi nào từ mỗi phương thức. Như thế thì lớp cha phục vụ như là một mẫu khái quát và tất cả các lớp con sẽ thừa kế từ nó. Các phương thức của lớp cha phục vụ như là một hợp đồng hay một chuẩn mà trong đó lớp con có thể thực thi theo hướng riêng của nó. Java cung cấp từ khóa 'abstract' để thực hiện nhiệm vụ này.

Như vậy, một phương thức trừu tượng sẽ được khai báo với từ khóa 'abstract' và không có phần thực thi, tức là không có phần thân. Phương thức trừu tượng không chứa cặp ngoặc xoắn ({}) và kết thúc là dấu chấm phẩy (;). Cú pháp khai báo một phương thức trừu tượng là như sau:

abstract <kiểu_trả_về> <tên_phương_thức> (<danh_sách_tham_số>);

trong đó, từ khóa abstract chỉ ra rằng phương thức là một phương thức trừu tượng.

Ví dụ,

public abstract void tinhToan();

Một lớp trừu tượng sẽ chứa các phương thức trừu tượng. Lớp trừu tượng sẽ phục vụ như là một framework trong đó cung cấp các hành vi cho các lớp khác. Có một lưu ý là các lớp trừu tượng không thể có phần thể hiện (không tạo được đối tượng từ lớp trừu tượng thông qua toán tử new) và chúng phải được phân lớp (các lớp con) để sử dụng các thành phần lớp. Lớp con sẽ thực thi các phương thức trừu tượng trong lớp cha của nó. Cú pháp khai báo một lớp trừu tượng là như sau:

abstract class <tên_lớp> {
  // Khai báo các trường
  // Định nghĩa các phương thức cụ thể
  //[Khai báo các phương thức trừu tượng]
}

trong đó, abstract chỉ ra rằng lớp và phương thức là trừu tượng.

Ví dụ:

abstract class MayTinh{
  public float getPI(){ // Định nghĩa một phương thức cụ thể
    return 3.14F;
  }
  abstract void tinhToan(); // Khai báo một phương thức trừu tượng
}

Đoạn mã 1 cho thấy việc tạo lớp và phương thức trừu tượng.

Đoạn mã 1:

abstract class HinhDang {
  private final float PI = 3.14F; // Biến để lưu giá trị của số PI
  /* Getter của biến PI */
  public float getPI() {
    return PI;
  }
  /* Khai báo phương thức trừu tượng */
  abstract void tinhToan(float giaTri);
}

Trong đoạn mã trên, lớp HinhDang là một lớp trừu tượng với một phương thức cụ thể là getPI() và một phương thức trừu tượng là tinhToan().

Để sử dụng lớp trừu tượng, ta cần tạo các lớp con. Đoạn mã 2 dưới đây tạo hai lớp con là HinhTron và ChuNhat.

Đoạn mã 2:

/* Định nghĩa lớp con HinhTron */
class HinhTron extends HinhDang {
  float dienTich; // Biến để lưu diện tích của hình tròn
  /* Thực thi phương thức trừu tượng để tính diện tích hình tròn */
  @Override void tinhToan(float banKinh) {
    dienTich = getPI() * banKinh * banKinh;
    System.out.println("Diện tích của hình tròn là: " + dienTich);
  }
}

/* Định nghĩa lớp con ChuNhat */
class ChuNhat extends HinhDang {
  float chuVi; // Biến lưu chu vi
  float chieuDai = 10; // Biến lưu chiều dài
  /* Thực thi phương thức trừu trượng để tính chu vi */
  @Override void tinhToan(float chieuRong) {
    chuVi = 2 * (chieuDai + chieuRong);
    System.out.println("Chu vi của hình chữ nhật là: " + chuVi);
  }
}

Lớp HinhTron thực thi phương thức trừu tượng tinhToan() để tính diện tích hình tròn. Tương tự, lớp ChuNhat thực thi phương thức tinhToan() để tính chu vi của hình chữ nhật.

Đoạn mã 3 mô tả mã lệnh của lớp MayTinh trong đó sử dụng các lớp con dựa trên các giá trị nhập vào từ người dùng.

Đoạn mã 3:

public class MayTinh {
  static Scanner sc = new Scanner(System.in);
  public static void main(String[] args) {
    HinhDang objHinhDang; // Khai báo 1 đối tượng của lớp HinhDang
    String hinhDang; // Biến lưu loại hình dạng
    System.out.print("Mời nhập hình dạng bạn muốn thao tác (HinhTron/ChuNhat): ");
    hinhDang = sc.nextLine();
    hinhDang = hinhDang.toLowerCase(); // chuyển sang chữ thường
    System.out.print("Mời bạn nhập chiều rộng: ");
    float rong = sc.nextFloat();
    switch (hinhDang) { // Kiểm tra hình dạng (phiên bản JDK7 trở lên switch mới hỗ trợ kiểu chuỗi)
      case "hinhtron":
        objHinhDang = new HinhTron();
        objHinhDang.tinhToan(rong);
        break;
      case "chunhat":
        objHinhDang = new ChuNhat();
        objHinhDang.tinhToan(rong);
        break;
      default:
        System.out.println("Bạn chỉ nhập được HinhTron hoặc ChuNhat");
    }
  }
}

Trong đoạn mã trên, bạn hãy để ý tới đối tượng objHinhDang của lớp HinhDang, ta đã đề cập ở phía đầu bài viết rằng một lớp trừu tượng không thể có thể hiện. Do đó, ta không thể viết là HinhDang objHinhDang = new HinhDang();. Tuy nhiên, một lớp trừu tượng có thể được quyền chỉ định một tham chiếu tới các lớp con của nó. Vì thế mà câu lệnh HinhDang objHinhDang; là hoàn toàn hợp lệ.

Câu lệnh switch kiểm tra hình dạng thông qua giá trị chuỗi chứa trong biến hinhDang (trước đó đã được chuyển thành chữ in thường bằng câu lệnh hinhDang = hinhDang.toLowerCase();) để gán tham chiếu cho phù hợp. Ví dụ, nếu hinhDang là hình tròn thì nó sẽ gán new HinhTron() như là tham chiếu, rồi khi sử dụng đối tượng objHinhDang thì phương thức tinhToan() ứng với lớp con được tham chiếu được gọi.

Tương tự, ta có thể cho một vài lớp khác thừa kế từ lớp trừu tượng HinhDang và thực thi phương thức tinhToan() theo yêu cầu.

» Tiếp: Interface (Giao diện)
« Trước: Đóng gói (Encapsulation)
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!