CHÀO! Hãy dành bài học hôm nay để đóng gói và bắt đầu ngay với các ví dụ :) Nguyên tắc đóng gói - 1Ở đây bạn có một máy soda bình thường . Tôi có một câu hỏi dành cho bạn: nó hoạt động như thế nào? Cố gắng đưa ra câu trả lời chi tiết: cốc đến từ đâu, nhiệt độ bên trong được duy trì như thế nào, đá được bảo quản ở đâu, làm sao máy biết nên thêm xi-rô nào, v.v.? Bạn có thể không có câu trả lời cho những câu hỏi này. Đủ công bằng, vì không phải ai cũng sử dụng những chiếc máy như vậy. Ngày nay chúng không quá phổ biến. Hãy thử đưa ra một ví dụ khác. Một cái gì đó mà bạn chắc chắn sử dụng nhiều lần mỗi ngày. Ồ, đây là một ý tưởng! Nguyên tắc đóng gói - 2Hãy cho chúng tôi biết cách thức hoạt động của công cụ tìm kiếm Googlelàm. Làm thế nào chính xác nó tìm kiếm thông tin liên quan đến các từ bạn nhập? Tại sao một số kết quả được xếp hạng cao mà không phải những kết quả khác? Mặc dù bạn sử dụng Google hàng ngày nhưng rất có thể bạn không biết. Nhưng nó không quan trọng. Bạn không cần phải biết điều này. Bạn có thể nhập các truy vấn vào một công cụ tìm kiếm mà không cần suy nghĩ về cách thức hoạt động của nó. Bạn có thể mua soda từ một chiếc máy mà không cần biết nó hoạt động như thế nào. Bạn có thể lái một chiếc ô tô mà không cần hiểu cách thức hoạt động của động cơ đốt trong và không cần biết gì về vật lý, kể cả ở cấp tiểu học. Tất cả điều này có thể thực hiện được nhờ một trong những nguyên tắc chính của lập trình hướng đối tượng: đóng gói. Đọc các bài viết khác nhau về lập trình hướng đối tượng (OOP), bạn hẳn đã bắt gặp một thực tế là lập trình bao gồm hai khái niệm phổ biến: đóng góiẩn . Và các tác giả sử dụng từ "đóng gói" để chỉ một thứ và sau đó là một thứ khác. Chúng ta sẽ khám phá cả hai thuật ngữ để bạn có được sự hiểu biết đầy đủ. Trong lập trình, ý nghĩa ban đầu của đóng góigói dữ liệu, cùng với các phương thức hoạt động trên dữ liệu đó, thành một đơn vị duy nhất (tức là "viên nang"). Trong Java, lớp là đơn vị đóng gói. Một lớp chứa cả dữ liệu (trường) và phương thức để làm việc với dữ liệu này.Nguyên tắc đóng gói - 3Điều này có vẻ như là cách tiếp cận rõ ràng đúng đối với bạn, nhưng trong các mô hình lập trình khác, mọi thứ được sắp xếp khác đi. Ví dụ, trong lập trình chức năng, dữ liệu được tách biệt hoàn toàn với các hoạt động trên đó. Trong OOP, các chương trình bao gồm các viên nang hoặc các lớp bao gồm cả dữ liệu và chức năng để làm việc với dữ liệu đó. Bây giờ hãy nói về ẩn . Làm thế nào mà chúng ta sử dụng tất cả các loại thiết bị phức tạp mà không hiểu cách chúng được tổ chức hoặc cách chúng hoạt động? Thật đơn giản: những người tạo ra chúng đã cung cấp cho chúng tôi một giao diện đơn giản và thuận tiện. Trên máy soda, giao diện là các nút trên bảng điều khiển. Nhấn một nút, bạn chọn cỡ cốc. Nhấn một lần nữa, bạn chọn hương vị. Một phần ba chịu trách nhiệm thêm đá. Và đó là tất cả những gì bạn cần làm. Tổ chức bên trong của máy không thành vấn đề. Điều quan trọng là nó được thiết kế theo cách yêu cầu người dùng nhấn ba nút để lấy soda . Điều này cũng đúng với ô tô. Nó không quan trọng những gì đang xảy ra bên trong. Điều quan trọng là khi bạn nhấn bàn đạp phải, xe sẽ tiến lên và khi bạn nhấn bàn đạp trái, nó sẽ đi chậm lại. Đó là những gì ẩn số lượng. Tất cả "phần bên trong" của chương trình đều bị ẩn đối với người dùng. Đối với người dùng, thông tin thừa, không cần thiết này. Người dùng cần kết quả cuối cùng, không phải quy trình nội bộ. Hãy xem Autolớp học làm ví dụ:

public class Auto {

   public void go() {

       /* Some complicated things happen inside the car.
       As a result, it moves forward */
   }

   public void brake() {

       /* Some complicated things happen inside the car.
       As a result, it slows down. */
   }

   public static void main(String[] args) {

       Auto auto = new Auto();

       // From the user's perspective,

       // one pedal is pressed and the car accelerates.
       auto.gas();
      
       // The other is pressed, and the car slows down.
       auto.brake();
   }
}
Đây là hình thức ẩn triển khai trong một chương trình Java. Nó giống như trong cuộc sống thực: người dùng được cung cấp một giao diện (phương thức). Nếu người dùng cần một chiếc ô tô trong chương trình để thực hiện một hành động, họ chỉ cần gọi phương thức mong muốn. Điều gì xảy ra bên trong các phương pháp này là không cần thiết. Điều quan trọng là mọi thứ hoạt động như bình thường. Ở đây chúng ta đang nói về ẩn triển khai . Bên cạnh đó, Java còn có tính năng ẩn dữ liệu . Chúng tôi đã viết về điều đó trong bài học về getters và setters , nhưng việc xem lại khái niệm này sẽ không hại gì. Ví dụ, chúng ta có một Catlớp:

public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

  
}
Có lẽ bạn nhớ vấn đề với lớp này từ bài học trước? Nếu chưa, chúng ta hãy ghi nhớ nó ngay bây giờ. Vấn đề là dữ liệu (các trường) của nó được mở cho tất cả mọi người — một lập trình viên khác có thể dễ dàng tạo một con mèo không tên có trọng lượng bằng 0 và tuổi -1000 năm:

public static void main(String[] args) {

   Cat cat = new Cat();
   cat.name = "";
   cat.age = -1000;
   cat.weight = 0;

}
Có thể bạn có thể theo dõi chặt chẽ xem liệu một trong những đồng nghiệp của bạn có tạo các đối tượng có trạng thái không hợp lệ hay không, nhưng sẽ tốt hơn nhiều nếu loại trừ khả năng tạo ra các "đối tượng không hợp lệ" như vậy. Nguyên tắc đóng gói - 4Các cơ chế sau đây giúp chúng tôi ẩn dữ liệu:
  1. công cụ sửa đổi truy cập ( riêng tư , được bảo vệ , gói mặc định )
  2. getters và setters
Ví dụ: chúng ta có thể đặt dấu kiểm ở đó để xem liệu có ai đó đang cố gắng gán một số âm cho tuổi của con mèo hay không. Như chúng tôi đã nói trước đó, tác giả của nhiều bài báo khác nhau về đóng gói đôi khi có nghĩa là kết hợp dữ liệu và phương thức, hoặc ẩn chúng hoặc cả hai (kết hợp và ẩn chúng). Java có cả hai cơ chế (điều này không nhất thiết đúng với các ngôn ngữ OOP khác), vì vậy ý ​​nghĩa cuối cùng là đúng nhất. Đóng gói mang lại cho chúng ta một số lợi thế quan trọng:
  1. Kiểm soát trạng thái chính xác của một đối tượng. Có những ví dụ về điều này ở trên. Một setter và private modifier đảm bảo rằng chương trình của chúng ta sẽ không có những con mèo có trọng lượng bằng 0.

  2. Thân thiện với người dùng thông qua một giao diện. Chỉ còn lại các phương pháp "tiếp xúc" với thế giới bên ngoài. Gọi các phương thức là đủ để có kết quả — hoàn toàn không cần đi sâu vào chi tiết về cách thức hoạt động của chúng.

  3. Thay đổi mã không ảnh hưởng đến người dùng. Chúng tôi thực hiện bất kỳ và tất cả các thay đổi bên trong các phương thức. Điều này không ảnh hưởng đến người dùng phương pháp: nếu trước đây mã đúng là "auto.gas()" để nhấn bàn đạp ga, thì nó sẽ tiếp tục như vậy. Thực tế là chúng ta đã thay đổi một cái gì đó bên trong phương thức gas() vẫn ẩn đối với người dùng: như trước đây, người gọi chỉ nhận được kết quả mong muốn.