שיעורים מופשטים בג'אווה

1. סקירה כללית

ישנם מקרים רבים בעת ביצוע חוזה בו אנו רוצים לדחות חלקים מסוימים ביישום שיסתיימו בהמשך. אנו יכולים להשיג זאת בקלות בג'אווה באמצעות שיעורים מופשטים.

במדריך זה נלמד את היסודות של שיעורי מופשט בג'אווה ובאילו מקרים הם יכולים להועיל.

2. מושגי מפתח לשיעורים מופשטים

לפני שצוללים מתי להשתמש בשיעור מופשט, בואו נסתכל על המאפיינים הרלוונטיים ביותר שלהם:

  • אנו מגדירים שיעור מופשט עם ה- תַקצִיר שינוי לפני מעמד מילת מפתח
  • ניתן לסווג מחלקה מופשטת, אך אי אפשר לייצר אותה
  • אם כיתה מגדירה אחת או יותר תַקצִיר שיטות, אז יש להכריז על הכיתה עצמה תַקצִיר
  • מעמד מופשט יכול להכריז הן על שיטות מופשטות והן על שיטות קונקרטיות
  • תת-מחלקה הנגזרת ממעמד מופשט חייבת ליישם את כל השיטות המופשטות של מחלקת הבסיס או להיות מופשטת בעצמה

כדי להבין טוב יותר מושגים אלה, ניצור דוגמה פשוטה.

בואו ונגיע למחלקת המופשט הבסיסית שלנו להגדיר את ה- API המופשט של משחק לוח:

BoardGame ClassGames מופשט ציבורי {// ... הצהרות שדה, בונים משחק מופשט ריק (); // ... שיטות קונקרטיות}

לאחר מכן, אנו יכולים ליצור תת-מחלקה המיישמת את ה- לְשַׂחֵק שיטה:

מחלקה ציבורית דמקה מרחיבה את BoardGame {play public void () {// ... יישום}}

3. מתי להשתמש בשיעורים מופשטים

עַכשָׁיו, בואו ננתח כמה תרחישים אופייניים שבהם עלינו להעדיף שיעורים מופשטים על פני ממשקים ושיעורי בטון:

  • אנו רוצים לתמצת פונקציונליות נפוצה במקום אחד (שימוש חוזר בקוד) אותו ישתתפו מחלקות משנה רבות הקשורות
  • עלינו להגדיר באופן חלקי ממשק API שקטעי המשנה שלנו יכולים להרחיב ולשכלל אותו בקלות
  • מחלקות המשנה צריכות לרשת שיטה או שדה נפוצים אחת או יותר עם מכניסת גישה מוגנת

בואו נזכור כי כל התרחישים הללו הם דוגמאות טובות לדבקות מלאה בירושה בעקרון פתוח / סגור.

יתר על כן, מכיוון שהשימוש בשיעורים מופשטים עוסק במשתמע בסוגי בסיס ותתי סוגים, אנו גם מנצלים את הפולימורפיזם.

שים לב ששימוש חוזר בקוד הוא סיבה משכנעת מאוד לשימוש בכיתות מופשטות, כל עוד נשמרת מערכת היחסים "is-a" בתוך היררכיית הכיתות.

ו- Java 8 מוסיף קמט נוסף עם שיטות ברירת מחדל, שלעתים יכולות לתפוס את מקומן של הצורך ליצור מחלקה מופשטת לגמרי.

4. היררכיה לדוגמא של קוראי קבצים

כדי להבין בצורה ברורה יותר את הפונקציונליות שהשיעורים המופשטים מביאים לשולחן, בואו נסתכל על דוגמה אחרת.

4.1. הגדרת מעמד מופשט בסיסי

לכן, אם היינו רוצים שיהיו מספר סוגים של קוראי קבצים, אנו עשויים ליצור מחלקה מופשטת שמקפלת את המשותף לקריאת קבצים:

מחלקה מופשטת ציבורית BaseFileReader {file path path מוגנת; BaseFileReader מוגן (Path filePath) {this.filePath = filePath; } נתיב ציבורי getFilePath () {return filePath; } רשימת ציבורי readFile () זורקת IOException {להחזיר Files.lines (filePath) .map (זה :: mapFileLine) .collect (Collectors.toList ()); } מוגן מופשט מחרוזת mapFileLine (קו מחרוזת); }

שים לב שעשינו filePath מוגן כך שתתי המעמדות יוכלו לגשת אליו במידת הצורך. יותר חשוב, השארנו משהו לא פעיל: כיצד לנתח שורת טקסט בפועל מתוכן הקובץ.

התוכנית שלנו היא פשוטה: בעוד שלשיעורי הבטון שלנו אין דרך מיוחדת לאחסן את נתיב הקובץ או לעבור על הקובץ, לכל אחד מהם תהיה דרך מיוחדת לשנות כל שורה.

במבט ראשון, BaseFileReader אולי נראה מיותר. עם זאת, זהו היסוד של עיצוב נקי וניתן להרחבה בקלות. מזה, אנו יכולים ליישם בקלות גרסאות שונות של קורא קבצים שיכולות להתמקד בהיגיון העסקי הייחודי שלהן.

4.2. הגדרת מחלקות משנה

יישום טבעי הוא ככל הנראה המרת תוכן קובץ לאותיות קטנות:

מחלקה ציבורית LowercaseFileReader מרחיב את BaseFileReader {public LowercaseFileReader (Path filePath) {super (filePath); } @Override ציבורית מחרוזת mapFileLine (קו מחרוזת) {return line.toLowerCase (); }}

או אחר יכול להיות כזה שממיר את תוכן הקובץ לאותיות גדולות:

class class UppercaseFileReader מרחיב את BaseFileReader {public UppercaseFileReader (Path filePath) {super (filePath); } @Override ציבורית מחרוזת mapFileLine (קו מחרוזת) {return line.toUpperCase (); }}

כפי שניתן לראות מהדוגמה הפשוטה הזו, כל תת-מחלקה יכולה להתמקד בהתנהגותה הייחודית מבלי צורך לציין היבטים אחרים של קריאת קבצים.

4.3. שימוש בתת-מחלקה

לבסוף, שימוש בכיתה שעוברת בירושה ממופשט אינו שונה מכל מעמד קונקרטי אחר:

@Test ציבורי בטל givenLowercaseFileReaderInstance_whenCalledreadFile_thenCorrect () זורק חריג {URL מיקום = getClass (). GetClassLoader (). GetResource ("files / test.txt") נתיב נתיב = Paths.get (location.toURI ()); BaseFileReader smallcaseFileReader = חדש LowercaseFileReader (נתיב); assertThat (lowcaseFileReader.readFile ()). isInstanceOf (List.class); }

לשם הפשטות, קובץ היעד ממוקם מתחת ל- src / main / resources / files תיקיה. לפיכך, השתמשנו במטעין מחלקות יישומים לקבלת הנתיב של קובץ הדוגמה. אל תהסס לבדוק את המדריך שלנו בנושא מעמיסי כיתה בג'אווה.

5. מסקנה

במאמר מהיר זה, למדנו את היסודות של שיעורי מופשט בג'אווה, ומתי להשתמש בהם להשגת הפשטה ולתמצת יישום משותף במקום אחד.

כרגיל, כל דגימות הקוד המוצגות במדריך זה זמינות ב- GitHub.