JavaRush /จาวาบล็อก /Random-TH /ทะเยอทะยานและผู้ตั้งค่า

ทะเยอทะยานและผู้ตั้งค่า

เผยแพร่ในกลุ่ม
สวัสดี! ในการบรรยายครั้งก่อน คุณได้เรียนรู้วิธีสร้างชั้นเรียนเต็มรูปแบบของคุณเองพร้อมสาขาและวิธีการต่างๆ แล้ว นี่เป็นความก้าวหน้าอย่างมาก ทำได้ดีมาก! แต่ตอนนี้ฉันต้องบอกความจริงอันไม่พึงประสงค์แก่คุณ เราไม่ได้สร้างชั้นเรียนของเราค่อนข้างถูกต้อง! ทำไม เมื่อมองแวบแรก ไม่มีข้อผิดพลาดในคลาสนี้:
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!");
   }
}
ในความเป็นจริงก็มี ลองนึกภาพว่าขณะนั่งอยู่ที่ทำงาน คุณเขียนชั้นเรียนแบบนี้Catซึ่งหมายถึงแมว และเขาก็กลับบ้าน ขณะที่คุณไม่อยู่ โปรแกรมเมอร์อีกคนก็มาทำงาน สร้างคลาสของตัวเองMainซึ่งเขาเริ่มใช้คลาสที่คุณCatเขียน
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
ไม่สำคัญว่าทำไมเขาถึงทำหรือเกิดขึ้นอย่างไร: บางทีคนๆ นั้นอาจจะเหนื่อยหรือนอนไม่เพียงพอ อีกสิ่งหนึ่งที่สำคัญ: คลาสปัจจุบันของเราCatอนุญาตให้คุณกำหนดค่าบ้าๆ ให้กับฟิลด์ได้ เป็นผลให้โปรแกรมมีวัตถุที่มีสถานะไม่ถูกต้อง เช่น แมวตัวนี้ที่มีอายุ -1,000 ปี ในที่สุดเราก็ทำผิดพลาดอะไร? เมื่อเราสร้างชั้นเรียน เราก็เปิดเผยข้อมูลของมัน สาขาnameและageอยู่weightในสาธารณสมบัติ สามารถเข้าถึงได้ทุกที่ในโปรแกรม: เพียงสร้างวัตถุCat- เพียงเท่านี้โปรแกรมเมอร์คนใดก็ตามก็สามารถเข้าถึงข้อมูลได้โดยตรงผ่านตัวดำเนินการ " ."
Cat cat = new Cat();
cat.name = "";
ที่นี่เราเข้าถึงฟิลด์โดยตรงnameและตั้งค่าของมัน เราจำเป็นต้องปกป้องข้อมูลของเราจากการรบกวนจากภายนอกที่ไม่ถูกต้อง สิ่งที่จำเป็นสำหรับสิ่งนี้? ขั้นแรก ตัวแปรอินสแตนซ์ทั้งหมด (ฟิลด์) จะต้องทำเครื่องหมายด้วยตัวprivateแก้ไข Private เป็นตัวแก้ไขการเข้าถึงที่เข้มงวดที่สุดใน Java หากคุณใช้มัน เขตข้อมูลของชั้นเรียนCatจะไม่สามารถเข้าถึงได้ภายนอก
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 class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";//error! The name field in the Cat class has private access!
   }
}
คอมไพเลอร์เห็นสิ่งนี้และก่อให้เกิดข้อผิดพลาดทันที ตอนนี้ทุ่งนาดูเหมือนจะได้รับการคุ้มครอง แต่ปรากฎว่าการเข้าถึงเหล่านั้นถูกปิด "อย่างแน่นหนา": โปรแกรมไม่สามารถรับน้ำหนักของแมวที่มีอยู่ได้หากจำเป็น นี่ไม่ใช่ตัวเลือกเช่นกัน: ในรูปแบบนี้ชั้นเรียนของเราแทบจะเป็นไปไม่ได้เลยที่จะใช้ ตามหลักการแล้ว เราต้องอนุญาตให้มีการเข้าถึงข้อมูลอย่างจำกัด:
  • โปรแกรมเมอร์คนอื่นๆ ควรสามารถสร้างออบเจ็กต์ได้Cat
  • พวกเขาควรจะสามารถอ่านข้อมูลจากวัตถุที่มีอยู่แล้วได้ (เช่น ได้รับชื่อหรืออายุของแมวที่มีอยู่แล้ว)
  • นอกจากนี้ยังควรกำหนดค่าฟิลด์ได้ด้วย แต่ในขณะเดียวกัน - เฉพาะค่าที่ถูกต้องเท่านั้น วัตถุของเราจะต้องได้รับการปกป้องจากสิ่งที่ไม่ถูกต้อง (ไม่ใช่ “อายุ = -1,000 ปี” และสิ่งที่คล้ายกัน)
รายการข้อกำหนดก็เพียงพอแล้ว! แต่ในความเป็นจริง ทั้งหมด นี้ทำได้อย่างง่ายดายโดยใช้วิธีการพิเศษ - gettersและsetters
ทะเยอทะยานและผู้ตั้งค่า - 2
ชื่อนี้มาจากภาษาอังกฤษว่า " get " - " receive " (เช่น "วิธีการรับค่าของฟิลด์") และset - " set " (เช่น "วิธีการตั้งค่าของฟิลด์") เรามาดูกันว่าพวกเขามีลักษณะอย่างไรโดยใช้คลาสของเราเป็นตัวอย่างCat:
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) {
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       this.weight = weight;
   }
}
อย่างที่คุณเห็นทุกอย่างค่อนข้างง่าย :) ชื่อของพวกเขาส่วนใหญ่มักประกอบด้วยคำว่าget/set + ชื่อของฟิลด์ที่พวกเขารับผิดชอบ ตัวอย่างเช่น วิธีการgetWeight()ส่งกลับค่าของเขตข้อมูลweightสำหรับวัตถุที่ถูกเรียก นี่คือลักษณะที่ปรากฏในโปรแกรม:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       String barsikName = barsik.getName();
       int barsikAge = barsik.getAge();
       int barsikWeight = barsik.getWeight();

       System.out.println("Cat name: " + barsikName);
       System.out.println("Cat's age: " + barsikAge);
       System.out.println("Weight of the cat: " + barsikWeight);
   }
}
เอาต์พุตคอนโซล:

Name кота: Барсик
Возраст кота: 5
Вес кота: 4
ตอนนี้จากคลาสอื่น ( Main) จะสามารถเข้าถึงฟิลด์ได้Catแต่จะผ่าน gettersเท่านั้น โปรดทราบว่า getters มี access modifier publicซึ่งหมายความว่าสามารถเข้าถึงได้จากทุกที่ในโปรแกรม แล้วการกำหนดค่าล่ะ? วิธีการ Setterมีหน้าที่รับผิดชอบในเรื่องนี้
public void setName(String name) {
   this.name = name;
}
อย่างที่คุณเห็นงานของพวกเขาก็เรียบง่ายเช่นกัน เราเรียกเมธอดsetName()บนอ็อบเจ็กต์Catส่งผ่านสตริงเป็นอาร์กิวเมนต์ และสตริงนี้ถูกกำหนดให้กับฟิลด์nameของอ็อบเจ็กต์ของเรา
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);

       System.out.println("The original name of the cat is " + barsik.getName());
       barsik.setName("Basil");
       System.out.println("The new name of the cat -" + barsik.getName());
   }
}
ที่นี่เราใช้ทั้ง getters และ setters ขั้นแรกโดยใช้ getter เราได้รับและส่งออกชื่อเริ่มต้นของ cat ไปยังคอนโซล จากนั้นเมื่อใช้ตัวตั้งค่าnameจะมีการกำหนดค่าใหม่ให้กับฟิลด์ - "Vasily" จากนั้นเมื่อใช้ getter เราได้ชื่ออีกครั้งเพื่อตรวจสอบว่ามีการเปลี่ยนแปลงจริงหรือไม่ เอาต์พุตคอนโซล:

Изначальное Name кота — Барсик
Новое Name кота — Васorй
ดูเหมือนว่าอะไรคือความแตกต่าง? นอกจากนี้เรายังสามารถกำหนดค่าที่ไม่ถูกต้องให้กับฟิลด์วัตถุได้แม้ว่าเราจะมีตัวตั้งค่า:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
เอาต์พุตคอนโซล:

Возраст Барсика — -1000 лет
ข้อแตกต่าง ก็ คือsetter เป็นวิธีการที่สมบูรณ์ และในวิธีการที่ไม่เหมือนกับฟิลด์ คุณสามารถใส่ตรรกะการตรวจสอบที่คุณต้องการเพื่อป้องกันค่าที่ยอมรับไม่ได้ ตัวอย่างเช่น คุณสามารถปิดใช้งานการกำหนดจำนวนลบเป็นอายุได้อย่างง่ายดาย:
public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("Error! Age cannot be negative!");
   }
}
และตอนนี้โค้ดของเราทำงานได้ถูกต้องแล้ว!
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
เอาต์พุตคอนโซล:

Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
มีข้อจำกัดในตัวตั้งค่า และจะป้องกันความพยายามในการตั้งค่าข้อมูลที่ไม่ถูกต้อง อายุของ Barsik ยังคงไม่เปลี่ยนแปลง ควรสร้าง Getters และ Setters เสมอ แม้ว่าฟิลด์ของคุณจะไม่มีข้อจำกัดเกี่ยวกับค่าที่เป็นไปได้ แต่ก็จะไม่เกิดอันตรายใดๆ ลองนึกภาพสถานการณ์: คุณและเพื่อนร่วมงานกำลังเขียนโปรแกรมด้วยกัน คุณสร้างคลาสCatที่มีช่องสาธารณะ และโปรแกรมเมอร์ทุกคนก็ใช้คลาสนั้นตามที่พวกเขาต้องการ แล้ววันหนึ่งที่ดีก็มาถึงคุณ: “ไม่ช้าก็เร็วอาจมีคนกำหนดจำนวนลบให้กับตัวแปรโดยไม่ได้ตั้งใจweight! เราจำเป็นต้องสร้างผู้ตั้งค่าและทำให้ทุกฟิลด์เป็นส่วนตัว!” คุณสร้างมันขึ้นมา และโค้ดทั้งหมดที่เพื่อนร่วมงานของคุณเขียนก็พังทันที ท้ายที่สุดแล้ว พวกเขาได้เขียนโค้ดจำนวนหนึ่งซึ่งเข้าถึงฟิลด์ได้Catโดยตรง แล้ว
cat.name = "Hippopotamus";
และตอนนี้ฟิลด์กลายเป็นส่วนตัวแล้วและคอมไพเลอร์ก็สร้างข้อผิดพลาดมากมาย!
cat.name = "Hippopotamus";//error! The name field of the Cat class has private access!
ในสถานการณ์เช่น นี้ เป็นการดีกว่าที่จะซ่อนฟิลด์และสร้าง getter-setters ตั้งแต่เริ่มต้น เพื่อนร่วมงานของคุณทุกคนจะใช้สิ่งเหล่านี้ และหากคุณรู้ตัวช้าว่าคุณจำเป็นต้องจำกัดค่าของฟิลด์ คุณก็แค่เพิ่มเช็คเข้าไปในตัวตั้งค่า และจะไม่มีใครทำลายโค้ดที่เขียนไว้แล้ว แน่นอนว่า หากคุณต้องการเข้าถึงฟิลด์ใดฟิลด์หนึ่งแบบอ่านอย่างเดียว คุณสามารถสร้าง getter หนึ่งรายการได้ “ภายนอก” นั่นคือ นอกชั้นเรียนของคุณ ควรเข้าถึงได้เฉพาะวิธีการเท่านั้น ข้อมูลจะต้องถูกซ่อนไว้
ทะเยอทะยานและผู้ตั้งค่า - 4
การเปรียบเทียบสามารถทำได้ด้วยโทรศัพท์มือถือ ลองนึกภาพว่าแทนที่จะเปิดโทรศัพท์มือถือทั่วไป คุณได้รับโทรศัพท์ที่มีเคสแบบเปิดซึ่งมีสายไฟ วงจร ฯลฯ ทั้งหมดอยู่ ยื่นออกมา. โทรศัพท์ใช้งานได้: หากคุณพยายามอย่างหนักและเล่นซอกับไดอะแกรม คุณอาจสามารถโทรออกได้ แต่คุณอาจจะแค่ทำลายมัน บริษัทผู้ผลิตจะให้อินเทอร์เฟซแก่คุณแทน: ลูกค้าเพียงกดหมายเลขที่ต้องการ กดปุ่มสีเขียวด้วยหูโทรศัพท์ และเริ่มการโทร และเขาไม่สนใจว่าเกิดอะไรขึ้นภายในวงจรและสายไฟ และวิธีการทำงานของพวกมัน ในตัวอย่างนี้ บริษัทมีการจำกัดการเข้าถึง "ภายใน" (ข้อมูล) ของโทรศัพท์ และเหลือเพียงอินเทอร์เฟซ (วิธีการ) ภายนอกเท่านั้น เป็นผลให้ลูกค้าได้รับสิ่งที่ต้องการ (โทรออก) และจะไม่ทำลายสิ่งใดภายในอย่างแน่นอน
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION