4 tính chất của lập trình hướng đối tượng trong Java

Trong bài viết này, mình sẽ nói về các khái niệm lập trình hướng đối tượng trong Java. Bởi vì Java như là một hình mẫu lý tưởng cho triết lý lập trình hướng đối tượng.

Vậy lập trình hướng đối tượng là gì? Đó chính là một kiểu lập trình với các khái niệm như Lớp (Class), Đối tượng (Object), Kế thừa (Inheritance), tính đóng gói (Encapsulation), Trừu tượng (Abstraction), Đa hình (Polymorphism) gọi tắt là OOP.

Phần lớn các ngôn ngữ lập trình giống như Java, C++, C#, Ruby… đều theo mô hình lập trình hướng đối tượng.

Qua bài viết này, chúng ta sẽ hiểu rõ bản chất các khái niệm cốt lõi của lập trình hướng đối tượng Java qua 4 tính chất của lập trình hướng đối tượng

  1. Kế thừa
  2. Đóng gói
  3. Trừu tượng
  4. Đa hình

Lập trình hướng đối tượng là gì?

Lập trình hướng đối tượng hay còn gọi là lập trình OOP là kỹ thuật lập trình mà tất cả các logic, yêu cầu thực tế đều được xây dựng xoay quanh các đối tượng.

Khi sử dụng OOP, chúng ta sẽ định nghĩa các class để mô hình hóa các đối tượng thực tế. Trong ứng dụng các class sẽ được khởi tạo thành các instance. Trong suốt thời gian ứng dụng chạy, các phương thức (method) của đối tượng này sẽ được gọi.

Trong thế giới thực, đối tượng là những thực thể tồn tại có trạng thái và hành vi.

Hướng tiếp cận này hiện đang rất thành công và đã trở thành một trong những khuôn mẫu phát triển phần mềm, đặc biệt là các phần mềm cho doanh nghiệp.

Ưu điểm của OOP

Do lập trình hướng đối tượng ra đời sau này, nên nó kế thừa và khắc phục được những nhược điểm của các mô hình lập trình trước đó.

Với 4 tính chất OOP đặc thù của mình, có thể nói lập trình hướng đối tượng rất thích hợp cho các ứng dụng dành cho doanh nghiệp.

Mình có thể liệt kê một số ưu điểm của OOP:

  • Khả năng mở rộng cao.
  • Có khả năng tái sử dụng rất tốt nhờ tính kế thừa.
  • Dễ quản lý code khi cần thêm tính năng.
  • Dễ học, đơn giản, dễ bảo trì…

Tính chất của lập trình hướng đối tượng

Chúng ta hãy bắt đầu với khái niệm đầu tiên của lập trình hướng đối tượng: Tính kế thừa

Tính kế thừa

Trong lập trình hướng đối tượng, các chương trình máy tính được thiết kế theo nguyên tắc là tất cả mọi thứ đều được xem là đối tượng và tương tác với những đối tượng khác.

Tính kế thừa là một khái niệm được hiểu những thuộc tính của một lớp có thể được kế thừa bởi một lớp khác. Nó giúp chúng ta có thể sử dụng lại code và thiết lập một mối quan hệ giữa các class khác nhau.

Như chúng ta thấy ở hình trên, một đứa trẻ kế thừa các thuộc tính của cha cậu ấy. Tương tự, trong Java, chúng ta sẽ có 2 class như bên dưới:

  • Lớp cha còn được hiểu là Lớp siêu cấp, Lớp cơ sở (Parent class hoặc Super class hay Base class)
  • Lớp con còn được hiểu Lớp phụ, Lớp dẫn xuất (Child class hoặc Sub class hoặc Derived class)

Một lớp kế thừa những thuộc tính được biết đến là một Sub class trong khi một lớp có các thuộc tính được kế thừa được gọi là Parent class.

Kế thừa được phân chia làm 4 loại:

Đơn kế thừa (Single Inheritance)

Đối với Đơn kế thừa, một lớp sẽ kế thừa những thuộc tính của một lớp khác. Nó cho phép một lớp con kế thừa những thuộc tính và hành vi(method) từ một lớp cha.

Điều này sẽ cho phép code khả năng tái sử dụng code cũng như thêm các tính năng mới vào các đoạn code hiện có.

Ở ví dụ bên dưới, Class A là lớp cha và Class B là lớp con với những thuộc tính và hành vi của  lớp cha.

Trong java thì để kế thừa, đơn giản là sử dụng từ khóa extend

Class A
{
---
}
Class B extends A {
---
}Code language: PHP (php)

Kế thừa kiểu Đa cấp (Multilevel Inheritance)

Khi một lớp được bắt nguồn từ một lớp mà cũng là lớp con (kế thừa từ một lớp khác). Tức là một lớp có nhiều hơn một cấp cha, kiểu kế thừa đó được gọi là kế thừa kiểu Đa cấp.

Hãy xem sơ đồ, Class B kế thừa các thuộc tính và hành vi của class A, và class C kế thừa các thuộc tính, hành vi của Class B. Ở đây, Class A là lớp cha của Class B và Class B là lớp cha của Class C.

Trong trường hợp này, Class C ngầm kế thừa các thuộc tính và hành vi của Class A thông qua Class B. Đó chính là kế thừa kiểu Đa cấp

Cách viết kế thừa kiểu đa cấp trong java cũng tương tự như đơn kế thừa

Class A{
---
}
Class B extends A{
---
}
Class C extends B{
---
}

Tìm hiểu khoá học lập trình Java Web trong 6 tháng!

Kế thừa thứ bậc (Hierarchical Inheritance)

Khi một lớp có nhiều hơn một lớp con hoặc nói cách khác là có nhiều hơn một lớp con có cùng chung một lớp cha, lúc này loại kế thừa này được gọi là thứ bậc (hierarchical).

Hãy xem sơ đồ bên trên, Class B and Class C là lớp con đang kế thừa chung lớp cha là Class A.

Cùng xem cấu trúng kế thừa thứ bậc trong Java.

Class A{
---
}
Class B extends A{
---
}
Class C extends A{
---
}

Kế thừa lai (Hybrid Inheritance)

Kế thừa lai là sự kết hợp của nhiều loại kế thừa và nhiều cấp kế thừa. Vì đa kế thừa không được hỗ trợ trong Java bởi vì nó dẫn đến sự mơ hồ, nên loại kế thừa này chỉ có thể thực hiện được thông qua Interface

Hãy xem sơ đồ trên, Class A là lớp cha của Class B và Class C. Trong khi Class B và Class C đều là lớp cha của Class D

Như vậy, bạn đã hiểu rõ về kế thừa trong lập trình hướng đối tượng rồi đúng không? Hãy cùng chuyển sang một dạng khái niệm lập trình hướng đối tượng khác đó là tính đóng gói (Encapsulation).

Tính đóng gói (Encapsulation)

Tính đóng gói là một cơ chế liên kết dữ liệu và code chung với nhau thành một đơn vị duy nhất. Nó cũng được hiểu với mục đích che giấu dữ liệu của bạn để đảm bảo toàn vẹn dữ liệu từ những chỉnh sửa bên ngoài.

Điều này có nghĩa là gì?

Cách tốt nhất để hiểu tính đóng gói là nhìn vào viên nang y tế bên dưới. Ở đây, thuốc luôn được an toàn bên trong viên nang.

Tương tự, thông qua việc đóng gói, các phương thức và biến của một lớp cũng được ẩn và an toàn.

Chúng ta thực hiện tính đóng gói trong Java bằng cách:

  • Định nghĩa các biến của lớp với phạm vi là private.
  • Chỉ cho phép truy cập vào các thuộc tính/biến của đối tượng thông qua hàm getter, setter.

Hãy xem đoạn code bên dưới để hiểu rõ hơn về tính đóng gói:

public class Employee {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
       this.name = name;
    }
    public static void main(String[] args) {
               // todo
    }
}

Mình đã tạo một Class Employee với biến name có phạm vi là private. Sau đó mình đã tạo các phương thức getter và setter. Thông qua đó, chúng ta có thể lấy và gán giá trị cho cho tên của một Employee.

Thông qua các phương thức này, bất kỳ lớp nào muốn truy xuất biến name đều phải sử dụng các phương thức getter và setter mà không thể được phép truy cập trực tiếp vào thuộc tính name.

Tìm hiểu khoá học lập trình Java Web trong 6 tháng!

Tính trừu tượng (Abstraction)

Tính trừu tượng hướng đến chất lượng của các ý tưởng hơn là các sự kiện. Về cơ bản, tính trừu tượng đề cập đến việc ẩn hay hiện các chi tiết cần thiết cho người dùng.

Hãy tưởng tượng rằng chúng ta có một cuộc gọi, chúng ta chỉ có thể lựa chọn nhấc máy hoặc từ chối cuộc gọi. Nhưng thực tế, có rất nhiều code chạy ngầm bên dưới. Nên bạn không thể biết được quá trình xử lý cuộc gọi, đó chính là ưu điểm của tính trừu tượng.

Do đó, tính trừu tượng giúp chúng ta giảm sự phức tạp. Có hai cách thực hiện tính trừu tượng như bên dưới:

  • Lớp trừu tượng (Abstract Class)
  • Giao diện (Interface)

Tìm hiểu khoá học lập trình Java Web trong 6 tháng!

Lớp trừu tượng (Abstract class)

Lớp trừu tượng trong java chứa từ khóa “abstract”.

Từ khóa abstract là gì? Nếu một lớp được định nghĩa là trừu tượng nó không thể được khởi tạo bằng toán từ “new“, có nghĩa là bạn không thể tạo instance từ một lớp trừu tượng. Ngoài ra, một lớp trừu tượng có thể chứa phương thức trừu tượng hoặc các phương thức bình thường.

Để sử dụng lớp trừu tượng, bắt buộc nó phải được một lớp khác kế thừa và override toàn toàn bộ abstract method.

Giao diện (Interface)

Một Interface trong Java là một tập hợp các phương thức trừu tượng (abstract). Một class triển khai một interface, do đó kế thừa các phương thức abstract của interface.

Một interface không phải là một lớp. Viết một interface giống như viết một lớp, nhưng chúng có 2 định nghĩa khác nhau. Một lớp mô tả các thuộc tính và hành vi của một đối tượng. Một interface chứa các hành vi mà một class triển khai.

Cùng nhau tìm hiểu kỹ hơn về Interface bằng ví dụ ‘ParentCar’ và các phương thức liên quan.

public interface ParentCar {
    // Thay đổi số
    public void changeGear( int newValue);
    // tăng tốc
    public void speedUp(int increment);
    // Phanh
    public void applyBrakes(int decrement);
}

Mọi chiếc oto đều có những hàng vi này phải không? Nhưng mỗi loại xe cụ thể lại thực hiện khác nhau

Giả sử bạn đang làm việc với ô tô số sàn, ở đó bạn phải tăng từng số từng cấp một. Nhưng nếu bạn đang làm việc với một chiếc xe tự động, thì hệ thống của bạn sẽ quyết định cách thay đổi số dựa trên đến tốc độ.

Do đó, không phải tất cả các lớp con của mình đều có cùng một logic được viết cho việc thay đổi số.

Tương tự với trường hợp tăng tốc. Giả sử bạn nhấn ga, tốc độ tăng lên10 km hoặc 15km. Nhưng giả sử một ai đó đang lái một chiếc siêu xe và nhấn ga, tốc độ tăng 30kms hoặc 50kms là chắc. Một lần nữa logic thay đổi

Giống như nhấn phanh, một người có thể có một hệ thống phanh mạnh mẽ hoặc không.

Vì tất cả các chức năng đều là common với tất cả các lớp con, nên mình đã tạo interface ‘ParentCar’ có tất các chức năng mà một ôtô đều phải có. Sau đó, từng loại  class ôtô cụ thể sẽ phải thực hiện các hành vi này.

public class Audi implements ParentCar {
    int speed = 0;
    int gear = 1;
    public void changeGear(int value) {
        gear = value;
    }
    public void speedUp(int increment) {
        speed = speed + increment;
    }
    public void applyBrakes(int decrement) {
        speed = speed - decrement;
    }
    void printStates() {
        System.out.println("speed:" + speed + "gear:" + gear);
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Audi A6 = new Audi();
        A6.speedUp(50);
        A6.printStates();
        A6.changeGear(4);
        A6.SpeedUp(100);
        A6.printStates();
    }
}

Tính đa hình (Polymorphism)

Đa hình có nghĩa là nhiều hình thức, trong đó ‘poly’ có nghĩa là nhiều, còn ‘morph’ có nghĩa là hình thức. Đa hình có thể là một biến, một chức năng hoặc một đối tượng được đưa vào nhiều hình thức.

Nói cách khác, đa hình cho phép bạn định nghĩa một giao diện hoặc một chức năng với nhiều cách cài đặt.

Để  hiểu hơn về đa hình, mình lấy ví dụ như thế này.

Cùng xem xét kịch bản thế giới thực này trong môn cricket, chúng ta đều biết rằng có một số loại người ném banh khác nhau (bowler), ví dụ bowlers nhanh, bowler tốc độ trung bình và xoay.

Như bạn thấy ở hình bên trên, lớp cha BowlerClass có 3 lớp con là FastPacer, MediumPacer và Spinner.

Lớp Bower có phương thức bowlingMethod() nơi tất cả các lớp con đều kế thừa phương thức này. Như chúng ta biết, tốc độ một trái banh bánh sẽ khác so với ném trung bình và ném banh xoáy cũng như trong cách chơi và kinh nghiệm của người ném banh,..v.v..

Tương tự như vậy, việc thực hiện bowling của phương thức bowlingMethod() cũng sẽ khác so với những bowler khác. Và cũng tương tự với class spinner.

Điểm chính ở thảo luận trên đơn giản là cùng một tên nhưng có nhiều xử lý khác nhau. Tất cả 3 lớp ở trên đều kế thừa phương thức bowlingMethod() nhưng cách thực hiện của từng lớp là hoàn toàn khác nhau.

Nguồn: https://vntalking.com/lap-trinh-huong-doi-tuong-java.html

Bài viết liên quan

Leave a Reply

Your email address will not be published.

TÀI LIỆU DEV WORLD
Cẩm nang phát triển bền vững với nghề lập trình!