CodeGym /จาวาบล็อก /สุ่ม /ตัวดัดแปลงการเข้าถึงใน Java
John Squirrels
ระดับ
San Francisco

ตัวดัดแปลงการเข้าถึงใน Java

เผยแพร่ในกลุ่ม
สวัสดี! ในบทเรียนวันนี้ เราจะทำความคุ้นเคยกับแนวคิดของตัวดัดแปลงการเข้าถึงและพิจารณาตัวอย่างวิธีการทำงานกับพวกมัน แน่นอนว่าการพูดว่า 'ทำความคุ้นเคย' นั้นไม่ถูกต้องซะทีเดียว เพราะคุณคุ้นเคยกับคำเหล่านี้ส่วนใหญ่แล้วจากบทที่แล้ว ในกรณีนี้เรามารีเฟรชความทรงจำของเราเกี่ยวกับจุดที่สำคัญที่สุด การเข้าถึงตัวดัดแปลงมักเป็นคำหลักที่ควบคุมการเข้าถึงส่วนต่าง ๆ ของรหัสของคุณ ทำไม 'บ่อยที่สุด'? เนื่องจากหนึ่งในนั้นถูกตั้งค่าเป็นค่าเริ่มต้นโดยไม่ต้องใช้คำหลัก :) Java มีตัวดัดแปลงการเข้าถึงสี่ตัว เราแสดงรายการตามลำดับจากเข้มงวดมากที่สุดถึง 'ผ่อนปรน' มากที่สุด:
  • ส่วนตัว;
  • เริ่มต้น (มองเห็นแพ็คเกจ);
  • มีการป้องกัน;
  • สาธารณะ.
ลองดูที่แต่ละรายการและระบุว่าเมื่อใดที่อาจมีประโยชน์ และเราจะยกตัวอย่าง :)

ตัวดัดแปลงส่วนตัว

ตัวแก้ไขการเข้าถึง  ส่วนตัว ป้องกัน ค่าเริ่มต้น สาธารณะ - 2ส่วนตัวคือตัวแก้ไขการเข้าถึงที่จำกัดที่สุด โดยจะจำกัดการมองเห็นข้อมูลและวิธีการให้อยู่ในคลาสเดียว คุณรู้จักตัวแก้ไขนี้จากบทเรียนเกี่ยวกับตัวรับและตัวตั้ง จำตัวอย่างนี้ได้ไหม

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;
   }
}
เราได้พิจารณาในบทเรียนที่แล้ว เราทำผิดพลาดอย่างร้ายแรงที่นี่: เราเปิดเผยข้อมูลของเราต่อสาธารณะ ซึ่งทำให้โปรแกรมเมอร์คนอื่นสามารถเข้าถึงฟิลด์ได้โดยตรงและเปลี่ยนค่าของพวกเขา ยิ่งไปกว่านั้น... ค่าเหล่านี้ถูกกำหนดโดยไม่มีการตรวจสอบใดๆ ซึ่งหมายความว่าโปรแกรมของเราสามารถสร้าง cat ชื่อ "" ที่มีอายุ -1,000 ปีและน้ำหนัก 0 เพื่อแก้ปัญหานี้ เราใช้ getters และ setters และยังใช้ตัวดัดแปลงส่วนตัวเพื่อจำกัดการเข้าถึงข้อมูล

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;
   }
}
โดยพื้นฐานแล้ว การจำกัดการเข้าถึงฟิลด์และการใช้ getters และ setters เป็นตัวอย่างที่พบบ่อยที่สุดของความเป็นส่วนตัวจะนำไปใช้ในงานจริง กล่าวอีกนัยหนึ่ง จุดประสงค์หลักของตัวดัดแปลงนี้คือเพื่อให้เกิดการห่อหุ้มในโปรแกรม อย่างไรก็ตาม สิ่งนี้ไม่ได้ใช้กับฟิลด์เท่านั้น ลองนึกภาพว่าในโปรแกรมของคุณมีเมธอดที่ใช้ฟังก์ชันที่ซับซ้อนมากๆ เราจะแนะนำอะไรเป็นตัวอย่างได้บ้าง สมมติว่าเมธอด readDataFromCollider() ของคุณยอมรับการป้อนที่อยู่ข้อมูล อ่านข้อมูลจาก Large Hadron Collider ในรูปแบบไบต์ แปลงข้อมูลนี้เป็นข้อความ เขียนลงในไฟล์ และพิมพ์ แม้แต่คำอธิบายของเมธอดก็ดูน่ากลัว ไม่ต้องพูดถึงโค้ดเลย :) เพื่อให้โค้ดอ่านง่ายขึ้น จะเป็นการดีที่สุดที่จะไม่เขียนตรรกะที่ซับซ้อนของเมธอดทั้งหมดไว้ในที่เดียว เราควรแยกการทำงานออกเป็นวิธีการต่างๆ ตัวอย่างเช่นreadByteData()เมธอดมีหน้าที่อ่านข้อมูล เมธอดconverterBytesToSymbols()จะแปลงข้อมูลที่อ่านจาก Collider เป็นข้อความ เมธอดsaveToFile()จะบันทึกข้อความที่ได้รับลงในไฟล์ และ เมธอด printColliderData()จะพิมพ์ไฟล์ข้อมูลของเรา ในท้ายที่สุด เมธอด readDataFromCollider() ของเรา จะง่ายกว่ามาก:

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
   }
}
อย่างไรก็ตาม ดังที่คุณจำได้จากบทเรียนเกี่ยวกับอินเทอร์เฟซ ผู้ใช้จะเข้าถึงได้เฉพาะอินเทอร์เฟซภายนอกเท่านั้น และ 4 วิธีของเราไม่ได้เป็นส่วนหนึ่งของมัน พวกเขาเป็นวิธีการช่วยเหลือ: เราสร้างขึ้นเพื่อปรับปรุงการอ่านโค้ดและไม่ยัดเยียดงานที่แตกต่างกันสี่งานให้เป็นวิธีเดียว คุณไม่จำเป็นต้องให้ผู้ใช้เข้าถึงวิธีการเหล่านี้ หากผู้ใช้สามารถเข้าถึง เมธอด converterBytesToSymbols()ได้เมื่อทำงานกับ Collider พวกเขามักจะสับสนกับเมธอดและสงสัยว่ามีไว้เพื่ออะไร ไบต์ใดที่ถูกแปลง? พวกเขามาจากไหน? ทำไมต้องแปลงเป็นข้อความ ตรรกะที่ดำเนินการในวิธีนี้ไม่ได้เป็นส่วนหนึ่งของอินเทอร์เฟซที่เปิดเผยต่อผู้ใช้ เฉพาะreadDataFromCollider()วิธีการเป็นส่วนหนึ่งของอินเทอร์เฟซ แล้วเราจะทำอย่างไรกับวิธี 'ภายใน' ทั้งสี่นี้ ขวา! ใช้ ตัวดัดแปลง ส่วนตัวเพื่อจำกัดการเข้าถึง การทำเช่นนี้ช่วยให้พวกเขาสามารถทำงานภายในชั้นเรียนได้อย่างสงบโดยไม่ทำให้ผู้ใช้สับสน ซึ่งไม่จำเป็นต้องรู้ตรรกะของแต่ละวิธี

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
   }
}

ตัวดัดแปลงที่ได้รับการป้องกัน

ตัวดัดแปลงที่เข้มงวดที่สุดถัดไปได้รับการป้องกัน ตัวแก้ไขการเข้าถึง  ส่วนตัว ป้องกัน ค่าเริ่มต้น สาธารณะ - 3ฟิลด์และเมธอดที่ทำเครื่องหมายโดย ตัวแก้ไขการเข้าถึง ที่ได้รับการป้องกันจะมองเห็นได้:
  • ในทุกคลาสรวมอยู่ในแพ็คเกจเดียวกับเรา
  • ภายในทุกคลาสที่สืบทอดคลาสของเรา
ในตอนแรก เป็นเรื่องยากที่จะจินตนาการว่าเมื่อใดอาจจำเป็น ไม่ต้องแปลกใจ: มีกรณีการใช้งานสำหรับการป้องกัน น้อย กว่าแบบส่วนตัว มาก และมีความเฉพาะเจาะจงมาก ลองนึกภาพว่าเรามี คลาสนามธรรม AbstractSecretAgentที่เป็นตัวแทนของสายลับในหน่วยสืบราชการลับบางแห่ง เช่นเดียวกับ แพ็คเกจ top_secretที่มีคลาสนี้และคลาสที่สืบทอดมา คลาสที่เป็นรูปธรรมเช่นFBISecretAgent , MI6SecretAgent , MossadSecretAgentและอื่น ๆ สืบทอดมา ภายในคลาสนามธรรม เราต้องการใช้ตัวนับตัวแทน จะเพิ่มขึ้นเมื่อมีการสร้างตัวแทนใหม่ในโปรแกรม แพ็คเกจ top_secret;

public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
แต่ตัวแทนของเราเป็นความลับ! ซึ่งหมายความว่าพวกเขาและไม่มีใครควรรู้ว่ามีอยู่กี่ตัว เราสามารถเพิ่ม ตัวดัดแปลง ที่ได้รับการป้องกันไปยังฟิลด์agent_counter ได้อย่างง่ายดาย จากนั้นอินสแตนซ์ของคลาสสายลับอื่น ๆ และคลาสอื่น ๆ ที่อยู่ในแพ็คเกจ top_secret ของเราจะได้รับค่าของมัน

public abstract class AbstractSecretAgent {

   protected static int agent_counter = 0;
}
และนั่นเป็นงานเฉพาะทางที่ต้องใช้ ตัวดัดแปลงที่ได้รับ การป้องกัน :)

ตัวแก้ไขที่มองเห็นได้ของแพ็คเกจ

ถัดไปในรายการคือ ตัวปรับแต่ง เริ่มต้นหรือที่เรียกว่าตัวปรับแต่งที่มองเห็นได้ของแพ็คเกจ คีย์เวิร์ดไม่ได้ระบุ เนื่องจาก Java จะใช้คีย์เวิร์ดนี้กับฟิลด์และเมธอดทั้งหมดโดยค่าเริ่มต้น หากคุณเขียนสิ่งต่อไปนี้ในรหัสของคุณ:

int x = 10
ตัวแปรxจะมีการเข้าถึงแพ็คเกจ นี้ มันง่ายที่จะจำว่ามันทำอะไร โดยพื้นฐานแล้วค่าเริ่มต้น = การสืบทอด ที่ได้รับการป้องกัน :) เช่นเดียวกับ ตัวดัดแปลงที่ ได้รับการป้องกันแอปพลิเคชันจะถูกจำกัด บ่อยที่สุด การเข้าถึง เริ่มต้นจะใช้ในแพ็คเกจที่มีคลาสยูทิลิตี้บางคลาสที่ไม่ได้ใช้ฟังก์ชันของคลาสอื่น ๆ ทั้งหมดในแพ็คเกจ ลองยกตัวอย่าง ลองนึกภาพว่าเรามีแพ็คเกจ 'บริการ' ประกอบด้วยคลาสต่างๆ ที่ทำงานกับฐานข้อมูล ตัวอย่างเช่น มี คลาส UserServiceที่อ่านข้อมูลผู้ใช้จากฐานข้อมูล นั่นคือCarServiceคลาสที่อ่านข้อมูลรถยนต์จากฐานข้อมูลเดียวกัน และคลาสอื่นๆ ซึ่งแต่ละคลาสจะทำงานกับอ็อบเจกต์บางประเภทและอ่านข้อมูลที่สอดคล้องกันจากฐานข้อมูล

package services;

public class UserService {
}

package services;

public class CarService {
}
แต่มันจะง่ายสำหรับข้อมูลในฐานข้อมูลที่จะอยู่ในรูปแบบหนึ่งและเราต้องการในอีกรูปแบบหนึ่ง ลองนึกภาพว่าวันเกิดของผู้ใช้ในฐานข้อมูลถูกจัดเก็บเป็น <TIMESTAMP WITH TIME ZONE>...

2014-04-04 20:32:59.390583+02
...และเราต้องการวัตถุที่ง่ายที่สุดแทน — a java.util.Date เพื่อแก้ปัญหานี้ ภายใน แพ็คเกจ บริการเราสามารถสร้างคลาสMapper พิเศษได้ มันจะรับผิดชอบในการแปลงข้อมูลจากฐานข้อมูลเป็นวัตถุ Java ที่เราคุ้นเคย คลาสตัวช่วยง่ายๆ เรามักจะประกาศคลาสทั้งหมดเป็นคลาสสาธารณะ ClassNameแต่นี่ไม่ใช่ข้อกำหนด เราสามารถประกาศคลาสตัวช่วยของ เราเป็นคลาส Mapper ในกรณีนี้ มันยังคงทำงานของมัน แต่ไม่มีใครมองเห็นได้นอก แพ็คเกจ บริการ !

package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
และนี่คือเหตุผลพื้นฐาน: ทำไมใครก็ตามที่อยู่นอกแพ็คเกจจำเป็นต้องเห็นคลาสตัวช่วยที่ใช้งานได้เฉพาะกับคลาสในแพ็คเกจนั้น

ตัวแก้ไขสาธารณะ

และสุดท้าย แต่ไม่ท้ายสุด ตัวแก้ไข สาธารณะ ! คุณพบตัวแก้ไขนี้ในวันแรกของ การ ศึกษาบน CodeGym ในครั้งแรกที่คุณเรียกใช้public static void main(String[] args) ตัวแก้ไขการเข้าถึง  ส่วนตัว ป้องกัน ค่าเริ่มต้น สาธารณะ - 4ตอนนี้คุณได้ศึกษาบทเรียนเกี่ยวกับอินเทอร์เฟซแล้ว จุดประสงค์ของอินเทอร์เฟซก็ชัดเจนสำหรับคุณแล้ว :) ท้ายที่สุดแล้ว ตัวแก้ไข สาธารณะถูกสร้างขึ้นเพื่อมอบบางสิ่งให้กับผู้ใช้ ตัวอย่างเช่น อินเทอร์เฟซของโปรแกรมของคุณ สมมติว่าคุณได้เขียนโปรแกรมแปลที่สามารถแปลข้อความภาษารัสเซียเป็นภาษาอังกฤษได้ คุณสร้าง เมธอด translate(String textInRussian)ที่ใช้ตรรกะที่จำเป็นทั้งหมด คุณทำเครื่องหมายวิธีนี้ด้วยคำว่าpublicและตอนนี้เป็นส่วนหนึ่งของอินเทอร์เฟซ:

public class Translator {

   public String translate(String textInRussian) {

       // Translates text from Russian to English
   }
}
คุณสามารถผูกวิธีนี้กับปุ่ม 'แปลภาษา' บนหน้าจอได้ เสร็จแล้ว! ทุกคนสามารถใช้งานได้ ส่วนของรหัสที่ทำเครื่องหมายด้วย ตัวแก้ไข สาธารณะนั้นมีไว้สำหรับผู้ใช้ปลายทาง ยกตัวอย่างในชีวิตจริงส่วนตัวคือกระบวนการทั้งหมดที่เกิดขึ้นภายในทีวี ส่วนสาธารณะคือปุ่มบนรีโมทคอนโทรลที่ใช้จัดการทีวี ยิ่งไปกว่านั้น ผู้ใช้ไม่จำเป็นต้องรู้ว่าโทรทัศน์ถูกสร้างขึ้นมาอย่างไรหรือทำงานอย่างไร รีโมทคอนโทรลคือชุดของ วิธี การสาธารณะ : on() , off() , nextChannel() , beforerChannel() , enlargeVolume() , reduceVolume()เป็นต้น เพื่อเสริมสิ่งที่คุณได้เรียนรู้ เราขอแนะนำให้คุณดูบทเรียนวิดีโอจากหลักสูตร Java ของเรา
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION