CodeGym /בלוג Java /Random-HE /גישה לשינויים ב-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;
   }
}
שקלנו את זה בשיעור קודם. עשינו כאן טעות חמורה: אנחנו מפרסמים את הנתונים שלנו, מה שאפשר למתכנתים אחרים לגשת ישירות לשדות ולשנות את הערכים שלהם. מה שכן... הערכים הללו הוקצו ללא כל בדיקה. משמעות הדבר היא שהתוכנית שלנו יכולה ליצור חתול בשם "" עם גיל של -1000 שנים ומשקל של 0. כדי לפתור בעיה זו, השתמשנו ב-getters ו-seters, וגם השתמשנו ב-modifier הפרטי כדי להגביל את הגישה לנתונים.
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;
   }
}
ביסודו של דבר, הגבלת הגישה לשדות והטמעת מגפרים ומגדירים הם הדוגמאות הנפוצות ביותר לאופן שבו פרטיים ישמשו בעבודה אמיתית. במילים אחרות, המטרה העיקרית של משנה זה היא להשיג אנקפסולציה בתוכנית. זה לא חל רק על שדות, אגב. תאר לעצמך שבתוכנית שלך יש שיטה המיישמת פונקציונליות מורכבת מאוד. מה אנחנו יכולים להציע כדוגמה? נניח ששיטת readDataFromCollider() שלך מקבלת כקלט כתובת נתונים, קוראת נתונים מ-Large Hadron Collider בפורמט בתים, ממירה נתונים אלה לטקסט, כותבת אותם לקובץ ומדפיסה אותם. אפילו תיאור של השיטה נראה מפחיד, שלא לדבר על הקוד :) כדי להפוך את הקוד לקריאה יותר, עדיף לא לכתוב את כל ההיגיון המורכב של השיטה במקום אחד. במקום זאת, עלינו לפרק את הפונקציונליות לשיטות נפרדות. לדוגמה, שיטת readByteData() אחראית לקריאת נתונים, שיטת convertBytesToSymbols() ממירה את הנתונים הנקראים מהקולידר לטקסט, שיטת 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
   }
}
עם זאת, כפי שתזכרו מהשיעור על ממשקים, המשתמש מקבל רק גישה לממשק החיצוני. וארבע השיטות שלנו אינן חלק מזה. הן שיטות עוזרות: יצרנו אותן כדי לשפר את קריאות הקוד וכדי לא לדחוס ארבע משימות שונות לשיטה אחת. אינך צריך לתת למשתמש גישה לשיטות אלו. אם למשתמשים יש גישה לשיטת convertBytesToSymbols() בזמן העבודה עם ה-colider, סביר להניח שהם פשוט יתבלבלו מהשיטה ויתהו למה היא מיועדת. אילו בתים מומרים? מאיפה הם באו? למה להמיר אותם לטקסט? ההיגיון המבוצע בשיטה זו אינו חלק מהממשק החשוף למשתמש. רק השיטה 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
...ובמקום זאת אנחנו צריכים את האובייקט הפשוט ביותר - java.util.Date . כדי לפתור בעיה זו, בתוך חבילת השירותים , אנו יכולים ליצור מחלקה מיוחדת של Mapper . זה יהיה אחראי להמרת נתונים ממסד הנתונים לאובייקטי Java המוכרים שלנו. כיתת עוזרים פשוטה. בדרך כלל אנו מצהירים על כל המחלקות כ- Public class ClassName , אך זו אינה דרישה. אנו יכולים להכריז על כיתת העוזרים שלנו פשוט כמאפרת כיתה . במקרה זה, זה עדיין עושה את העבודה שלו, אבל זה לא גלוי לאף אחד מחוץ לחבילת השירותים !
package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
והנה הנימוק הבסיסי: למה שמישהו מחוץ לחבילה יצטרך לראות כיתת עוזר שעובדת רק עם הכיתות בחבילה הזו?

השינוי הציבורי

ואחרון חביב, המשנה הציבורי ! פגשת את השינוי הזה ביום הלימודים הראשון שלך ב-CodeGym בפעם הראשונה שהרצת את main(String[] args) public static void . משנה גישה.  פרטי, מוגן, ברירת מחדל, ציבורי - 4כעת, לאחר שלמדת את השיעור על ממשקים, מטרתו ברורה לך :) הרי ה- Public Modifier נוצר כדי לתת משהו למשתמשים. לדוגמה, הממשק של התוכנית שלך. נניח שכתבת תוכנית מתרגם שיכולה לתרגם טקסט רוסי לאנגלית. יצרת שיטת translate(String textInRussian) המיישמת את כל ההיגיון הדרוש. סימנת את השיטה הזו במילה public , ועכשיו היא חלק מהממשק:
public class Translator {

   public String translate(String textInRussian) {

       // Translates text from Russian to English
   }
}
אתה יכול לאגד את השיטה הזו לכפתור 'תרגם' במסך וסיימת! כל אחד יכול להשתמש בו. חלקי הקוד המסומנים בשינוי הציבורי מיועדים למשתמש הקצה. מתן דוגמה מהחיים האמיתיים, פרטי מיועד לכל התהליכים המתרחשים בתוך טלוויזיה, אך ציבורי מיועד ללחצנים בשלט הרחוק המשמשים לניהול הטלוויזיה. מה גם שהמשתמש לא צריך לדעת איך הטלוויזיה בנויה או איך היא פועלת. השלט הרחוק הוא קבוצת השיטות הציבוריות : on() , off() , nextChannel() , previousChannel() , increaseVolume() , lowerVolume() וכו'. כדי לחזק את מה שלמדת, אנו מציעים לך לצפות בשיעור וידאו מ- קורס Java שלנו
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION