CodeGym/Blog Java/Ngẫu nhiên/Công cụ sửa đổi truy cập trong Java

Công cụ sửa đổi truy cập trong Java

Xuất bản trong nhóm
CHÀO! Trong bài học hôm nay, chúng ta sẽ làm quen với khái niệm access modifiers và xem xét các ví dụ về cách làm việc với chúng. Tất nhiên, nói 'làm quen' không hoàn toàn đúng: bạn đã quen thuộc với hầu hết chúng từ các bài học trước. Để đề phòng, hãy làm mới trí nhớ của chúng ta về điểm quan trọng nhất. Quyền truy cập công cụ sửa đổi thường là các từ khóa quy định quyền truy cập vào các phần khác nhau trong mã của bạn. Tại sao 'thường xuyên nhất'? Bởi vì một trong số chúng được đặt theo mặc định mà không cần sử dụng từ khóa :) Java có bốn công cụ sửa đổi truy cập. Chúng tôi liệt kê chúng theo thứ tự từ hạn chế nhất đến 'khoan dung' nhất:
  • riêng tư;
  • mặc định (hiển thị gói);
  • được bảo vệ;
  • công cộng.
Chúng ta hãy xem xét từng người trong số họ và xác định khi nào họ có thể hữu ích. Và chúng tôi sẽ đưa ra ví dụ :)

Công cụ sửa đổi riêng

Công cụ sửa đổi truy cập.  Riêng tư, được bảo vệ, mặc định, công khai - 2private là công cụ sửa đổi quyền truy cập hạn chế nhất. Nó giới hạn khả năng hiển thị của dữ liệu và phương thức trong một lớp duy nhất. Bạn biết công cụ sửa đổi này từ bài học về getters và setters. Hãy nhớ ví dụ này?
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!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
Chúng ta đã xem xét nó trong một bài học trước. Chúng tôi đã mắc một sai lầm nghiêm trọng ở đây: Chúng tôi công khai dữ liệu của mình, điều này cho phép các lập trình viên đồng nghiệp truy cập trực tiếp vào các trường và thay đổi giá trị của chúng. Hơn nữa... những giá trị này được chỉ định mà không có bất kỳ sự kiểm tra nào. Điều này có nghĩa là chương trình của chúng tôi có thể tạo ra một con mèo có tên "" với tuổi -1000 và trọng lượng bằng 0. Để giải quyết vấn đề này, chúng tôi đã sử dụng getters và setters, đồng thời sử dụng công cụ sửa đổi riêng để hạn chế quyền truy cập vào dữ liệu.
public class Cat {

   private String name;
   private int age;
   private 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!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       // input parameter check
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       // input parameter check
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       // input parameter check
       this.weight = weight;
   }
}
Về cơ bản, giới hạn quyền truy cập vào các trường và triển khai getters và setters là những ví dụ phổ biến nhất về mức độ riêng tưsẽ được sử dụng trong công việc thực tế. Nói cách khác, mục đích chính của công cụ sửa đổi này là đạt được sự đóng gói trong một chương trình. Nhân tiện, điều này không chỉ áp dụng cho các trường. Hãy tưởng tượng rằng trong chương trình của bạn có một phương thức thực hiện một số chức năng RẤT phức tạp. Những gì chúng ta có thể đề nghị như là một ví dụ? Giả sử phương thức readDataFromCollider() của bạn chấp nhận đầu vào là địa chỉ dữ liệu, đọc dữ liệu từ Máy Va chạm Hadron Lớn ở định dạng byte, chuyển đổi dữ liệu này thành văn bản, ghi vào tệp và in ra. Ngay cả phần mô tả của phương thức cũng trông đáng sợ chứ đừng nói gì đến mã :) Để làm cho mã dễ đọc hơn, tốt nhất là không viết tất cả logic phức tạp của phương thức vào một chỗ. Thay vào đó, chúng ta nên chia chức năng thành các phương thức riêng biệt. Ví dụ, readByteData()phương thức chịu trách nhiệm đọc dữ liệu, phương thức convertBytesToSymbols() chuyển đổi dữ liệu được đọc từ máy va chạm thành văn bản, phương thức saveToFile() lưu văn bản nhận được vào một tệp và phương thức printColliderData() in tệp dữ liệu của chúng ta. Cuối cùng, phương thức readDataFromCollider() của chúng ta sẽ đơn giản hơn nhiều:
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   public byte[] readByteData(Path pathToData) {

       // Reads data in bytes
   }

   public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {

       // Converts bytes to characters
   }

   public File saveToFile(String[] colliderData) {

       // Saves read data to a file
   }

   public void printColliderData(File fileWithColliderData) {

       // Prints data from the file
   }
}
Tuy nhiên, như bạn sẽ nhớ từ bài học về giao diện, người dùng chỉ có quyền truy cập vào giao diện bên ngoài. Và 4 phương pháp của chúng tôi không phải là một phần của nó. Chúng là các phương thức trợ giúp: chúng tôi đã tạo chúng để cải thiện khả năng đọc mã và không nhồi nhét bốn tác vụ khác nhau vào một phương thức. Bạn không cần cấp cho người dùng quyền truy cập vào các phương pháp này. Nếu người dùng có quyền truy cập vào phương thức convertBytesToSymbols() khi làm việc với máy va chạm, rất có thể họ sẽ bị nhầm lẫn bởi phương thức này và tự hỏi nó dùng để làm gì. Những byte nào được chuyển đổi? Họ đến từ đâu vậy? Tại sao chuyển đổi chúng thành văn bản? Logic được thực hiện trong phương pháp này không phải là một phần của giao diện hiển thị cho người dùng. Chỉ readDataFromCollider()phương pháp là một phần của giao diện. Vậy chúng ta phải làm gì với bốn phương pháp 'nội bộ' này? Phải! Sử dụng công cụ sửa đổi riêng để giới hạn quyền truy cập vào chúng. Làm điều này cho phép họ thực hiện công việc của mình trong lớp một cách yên bình mà không gây nhầm lẫn cho người dùng, những người không cần biết logic của từng phương thức riêng lẻ.
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   private byte[] readByteData(Path pathToData) {
       // Reads data in bytes
   }

   private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
       // Converts bytes to characters
   }

   private File saveToFile(String[] colliderData) {
       // Saves read data to a file
   }

   private void printColliderData(File fileWithColliderData) {
       // Prints data from the file
   }
}

Công cụ sửa đổi được bảo vệ

Công cụ sửa đổi hạn chế nhất tiếp theo được bảo vệ . Công cụ sửa đổi truy cập.  Riêng tư, được bảo vệ, mặc định, công khai - 3Các trường và phương thức được đánh dấu bởi công cụ sửa đổi quyền truy cập được bảo vệ sẽ hiển thị:
  • trong tất cả các lớp được bao gồm trong cùng một gói như gói của chúng tôi;
  • trong tất cả các lớp kế thừa lớp của chúng ta.
Lúc đầu, thật khó để tưởng tượng khi nào điều này có thể cần thiết. Đừng ngạc nhiên: có ít trường hợp sử dụng protected hơn nhiều so với private và chúng rất cụ thể. Hãy tưởng tượng rằng chúng ta có một lớp trừu tượng AbstractSecretAgent đại diện cho một đặc vụ bí mật trong một số dịch vụ tình báo, cũng như một gói top_secret chứa lớp này và các phần tử con của nó. Các lớp cụ thể như FBISecretAgent , MI6SecretAgent , MossadSecretAgent , v.v. kế thừa nó. Bên trong lớp trừu tượng, chúng tôi muốn triển khai bộ đếm tác nhân. Nó sẽ tăng lên khi một tác nhân mới được tạo ở đâu đó trong chương trình. gói hàng đầu_bí mật;
public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
Nhưng đại lý của chúng tôi là bí mật! Điều này có nghĩa là họ và không ai khác nên biết có bao nhiêu trong số chúng tồn tại. Chúng ta có thể dễ dàng thêm công cụ sửa đổi được bảo vệ vào trường agent_counter . Sau đó, các phiên bản của các lớp đặc vụ bí mật khác và các lớp khác nằm trong gói top_secret của chúng tôi có thể nhận được giá trị của nó.
public abstract class AbstractSecretAgent {

   protected static int agent_counter = 0;
}
Và đó là loại nhiệm vụ chuyên biệt yêu cầu công cụ sửa đổi được bảo vệ :)

Công cụ sửa đổi có thể nhìn thấy gói

Tiếp theo trong danh sách là công cụ sửa đổi mặc định , còn được gọi là công cụ sửa đổi gói hiển thị . Nó không được biểu thị bằng một từ khóa, vì Java áp dụng nó theo mặc định cho tất cả các trường và phương thức. Nếu bạn viết như sau trong mã của bạn:
int x = 10
biến x sẽ có quyền truy cập hiển thị gói này . Thật dễ dàng để nhớ những gì nó làm. Về cơ bản, mặc định = kế thừa được bảo vệ :) Giống như công cụ sửa đổi được bảo vệ , ứng dụng của nó bị hạn chế. Thông thường, quyền truy cập mặc định được sử dụng trong gói có một số lớp tiện ích không triển khai chức năng của tất cả các lớp khác trong gói. Hãy đưa ra một ví dụ. Hãy tưởng tượng rằng chúng ta có một gói 'dịch vụ'. Nó chứa các lớp khác nhau hoạt động với cơ sở dữ liệu. Ví dụ: có một lớp UserService đọc dữ liệu người dùng từ cơ sở dữ liệu, một CarServicelớp đọc dữ liệu ô tô từ cùng một cơ sở dữ liệu và các lớp khác, mỗi lớp làm việc với các loại đối tượng cụ thể và đọc dữ liệu tương ứng từ cơ sở dữ liệu.
package services;

public class UserService {
}

package services;

public class CarService {
}
Nhưng thật dễ dàng để dữ liệu trong cơ sở dữ liệu ở một định dạng và chúng ta cần nó ở một định dạng khác. Hãy tưởng tượng rằng ngày sinh của người dùng trong cơ sở dữ liệu được lưu trữ dưới dạng <DẤU THỜI GIAN VỚI Múi giờ>...
2014-04-04 20:32:59.390583+02
...và thay vào đó chúng ta cần đối tượng đơn giản nhất — java.util.Date . Để giải quyết vấn đề này, bên trong gói dịch vụ , chúng ta có thể tạo một lớp Mapper đặc biệt . Nó sẽ chịu trách nhiệm chuyển đổi dữ liệu từ cơ sở dữ liệu sang các đối tượng Java quen thuộc của chúng ta. Một lớp trợ giúp đơn giản. Chúng tôi thường khai báo tất cả các lớp là lớp công khai ClassName , nhưng đây không phải là một yêu cầu. Chúng ta có thể khai báo lớp trình trợ giúp của mình đơn giản là lớp Mapper . Trong trường hợp này, nó vẫn thực hiện công việc của mình, nhưng nó không hiển thị với bất kỳ ai bên ngoài gói dịch vụ !
package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
Và đây là lý do cơ bản: tại sao những người bên ngoài một gói lại cần xem một lớp trợ giúp chỉ hoạt động với các lớp trong gói đó?

Công cụ sửa đổi công khai

Và cuối cùng nhưng không kém phần quan trọng, công cụ sửa đổi công khai ! Bạn đã gặp công cụ sửa đổi này vào ngày đầu tiên học trên CodeGym khi lần đầu tiên bạn chạy public static void main(String[] args) . Công cụ sửa đổi truy cập.  Riêng tư, được bảo vệ, mặc định, công khai - 4Bây giờ bạn đã học bài học về giao diện, mục đích của nó là hiển nhiên đối với bạn rồi :) Xét cho cùng, công cụ sửa đổi công khai được tạo ra để cung cấp thứ gì đó cho người dùng. Ví dụ, giao diện chương trình của bạn. Giả sử bạn đã viết một chương trình dịch có thể dịch văn bản tiếng Nga sang tiếng Anh. Bạn đã tạo một phương thức translate(String textInRussian) thực hiện tất cả logic cần thiết. Bạn đã đánh dấu phương thức này bằng từ public và bây giờ nó là một phần của giao diện:
public class Translator {

   public String translate(String textInRussian) {

       // Translates text from Russian to English
   }
}
Bạn có thể liên kết phương thức này với nút 'Dịch' trên màn hình và bạn đã hoàn tất! Bất cứ ai cũng có thể sử dụng nó. Các phần mã được đánh dấu bằng công cụ sửa đổi công khai dành cho người dùng cuối. Cung cấp một ví dụ thực tế, riêng tư dành cho tất cả các quy trình xảy ra bên trong TV, nhưng công khai dành cho các nút trên điều khiển từ xa được sử dụng để quản lý TV. Hơn nữa, người dùng không cần biết tivi được chế tạo như thế nào hoặc nó hoạt động như thế nào. Điều khiển từ xa là tập hợp các phương thức công khai : on() , off() , nextChannel() , previousChannel() , gainVolume() , reduceVolume() v.v. Để củng cố những gì bạn đã học, chúng tôi khuyên bạn nên xem một video bài học từ Khóa học Java của chúng tôi
Bình luận
  • Phổ biến
  • Mới
Bạn phải đăng nhập để đăng nhận xet
Trang này chưa có bất kỳ bình luận nào