JavaRush /בלוג Java /Random-HE /כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים

כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים

פורסם בקבוצה
צהריים טובים לכולם: היום אני רוצה לדבר איתך על כתיבת קוד נכון. כשהתחלתי לתכנת, לא היה כתוב בבירור בשום מקום שאתה יכול לכתוב ככה, ואם אתה כותב ככה, אני אמצא אותך ו... כתוצאה מכך עלו לי הרבה שאלות בראש: איך כותבים נכון, על איזה עקרונות יש להקפיד בחלק זה או אחר בתוכנית וכו'. כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 1ובכן, לא כולם רוצים לצלול מיד לספרים כמו Clean Code, שכן כתוב בהם הרבה, אבל בהתחלה מעט ברור. ועד שתסיים לקרוא, אתה יכול להרתיע כל רצון לקוד. אז בהתבסס על האמור לעיל, היום אני רוצה לספק לכם מדריך קטן (סט של המלצות קטנות) לכתיבת קוד ברמה גבוהה יותר. במאמר זה נעבור על הכללים והמושגים הבסיסיים הנוגעים ליצירת מערכת ועבודה עם ממשקים, מחלקות ואובייקטים. קריאת החומר הזה לא תיקח לך הרבה זמן, ואני מקווה שלא תאפשר לך להשתעמם. אני אעבור מלמעלה למטה, כלומר מהמבנה הכללי של האפליקציה לפרטים ספציפיים יותר. כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 2

מערכת

המאפיינים הכלליים הרצויים של המערכת הם:
  • מורכבות מינימלית - יש להימנע מפרויקטים מסובכים מדי. העיקר הוא פשטות ובהירות (הכי טוב = פשוט);
  • קלות תחזוקה - בעת יצירת אפליקציה, עליך לזכור כי יהיה צורך לתמוך בה (גם אם זה לא אתה), ולכן הקוד צריך להיות ברור וברור;
  • צימוד חלש הוא המספר המינימלי של חיבורים בין חלקים שונים של התוכנית (שימוש מרבי בעקרונות OOP);
  • שימוש חוזר - תכנון מערכת עם יכולת לעשות שימוש חוזר בפרגמנטים שלה ביישומים אחרים;
  • ניידות - יש להתאים את המערכת בקלות לסביבה אחרת;
  • סגנון יחיד - עיצוב מערכת בסגנון יחיד על שבריה השונים;
  • הרחבה (מדרגיות) - שיפור המערכת מבלי להפריע למבנה הבסיסי שלה (אם אתה מוסיף או משנה קטע, זה לא אמור להשפיע על השאר).
כמעט בלתי אפשרי לבנות אפליקציה שאינה דורשת שינויים, מבלי להוסיף פונקציונליות. נצטרך כל הזמן להציג אלמנטים חדשים כדי שיוכלנו יוכל לעמוד בקצב הזמן. וכאן נכנסת לתמונה המדרגיות . מדרגיות היא בעצם הרחבת האפליקציה, הוספת פונקציונליות חדשה, עבודה עם יותר משאבים (או, במילים אחרות, עם יותר עומס). כלומר, עלינו להקפיד על כמה כללים, כמו הפחתת הצימוד של המערכת על ידי הגברת המודולריות, כך שיהיה קל יותר להוסיף היגיון חדש.

שלבי תכנון המערכת

  1. מערכת תוכנה - עיצוב אפליקציה בצורה כללית.
  2. הפרדה לתת-מערכות/חבילות - הגדרת חלקים הניתנים להפרדה לוגית והגדרת כללי האינטראקציה ביניהם.
  3. חלוקת תתי מערכות למחלקות - חלוקת חלקים מהמערכת למחלקות וממשקים ספציפיים, וכן הגדרת האינטראקציה ביניהם.
  4. חלוקת מחלקות לשיטות היא הגדרה מלאה של המתודות הנחוצות למחלקה, בהתבסס על המשימה של מחלקה זו. עיצוב שיטה - הגדרה מפורטת של הפונקציונליות של שיטות בודדות.
בדרך כלל, מפתחים רגילים אחראים לתכנון, וארכיטקט האפליקציה אחראי לפריטים שתוארו לעיל.

עקרונות ותפיסות עיקריות של עיצוב מערכת

ניב אתחול עצלן יישום אינו משקיע זמן ביצירת אובייקט עד לשימוש בו, מה שמאיץ את תהליך האתחול ומפחית את עומס אוספי האשפה. אבל אתה לא צריך ללכת רחוק מדי עם זה, שכן זה יכול להוביל להפרה של מודולריות. אולי כדאי להעביר את כל שלבי התכנון לחלק מסוים, למשל, ראשי, או לכיתה שעובדת כמו מפעל . אחד ההיבטים של קוד טוב הוא היעדר קוד שחוזר על עצמו תדיר. ככלל, קוד כזה ממוקם בכיתה נפרדת כך שניתן יהיה לקרוא לו בזמן הנכון. AOP בנפרד, אני רוצה להזכיר תכנות מונחה היבטים . זהו תכנות על ידי הכנסת לוגיקה מקצה לקצה, כלומר, קוד חוזר מוכנס למחלקות - היבטים, ונקרא כאשר מגיעים לתנאים מסוימים. למשל, בעת גישה למתודה עם שם מסוים או גישה למשתנה מסוג מסוים. לפעמים היבטים יכולים לבלבל, מכיוון שלא ברור מיד מאיפה נקרא הקוד, אבל בכל זאת, זוהי פונקציונליות שימושית מאוד. בפרט, בעת אחסון במטמון או רישום: אנו מוסיפים פונקציונליות זו מבלי להוסיף היגיון נוסף למחלקות רגילות. אתה יכול לקרוא עוד על OAP כאן . 4 כללים לעיצוב אדריכלות פשוטה על פי קנט בק
  1. כושר ביטוי – הצורך במטרה מפורשת של הכיתה, מושג באמצעות מתן שמות נכון, גודל קטן והקפדה על עיקרון האחריות הבודדת (נראה זאת בהרחבה בהמשך).
  2. מינימום שיעורים ושיטות - ברצונכם לחלק שיעורים לכמה שיותר קטנים וחד-כיווניים, אתם יכולים ללכת רחוק מדי (אנטי-פטרן - shotgunning). עיקרון זה דורש לשמור על המערכת קומפקטית ולא ללכת רחוק מדי, ליצור מעמד לכל עיטוש.
  3. חוסר כפילות – קוד נוסף שמבלבל מעיד על תכנון לקוי של המערכת ומועבר למקום נפרד.
  4. ביצוע כל הבדיקות – מערכת שעברה את כל המבחנים מבוקרת שכן כל שינוי עלול לגרום לכישלון הבדיקות מה שיכול להראות לנו ששינוי בלוגיקה הפנימית של השיטה הוביל גם לשינוי בהתנהגות הצפויה.
SOLID כאשר מתכננים מערכת, כדאי לקחת בחשבון את העקרונות הידועים של SOLID: S - אחריות יחידה - עקרון האחריות היחידה; O - פתוח-סגור - עקרון הפתיחות/סגירה; L - החלפת ליסקוב - עקרון ההחלפה של ברברה ליסקוב; I - הפרדת ממשקים - עקרון הפרדת הממשק; D - היפוך תלות - עקרון היפוך התלות; לא נתעכב על כל עיקרון ספציפית (זה קצת מעבר לתחום המאמר הזה, אבל אתה יכול לגלות עוד כאן

מִמְשָׁק

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

מעמד

כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 3בואו נסתכל על הארגון הפנימי של השיעורים. או ליתר דיוק, כמה דעות וכללים שיש להקפיד עליהם בעת בניית כיתות. בדרך כלל, מחלקה צריכה להתחיל עם רשימה של משתנים, מסודרת בסדר מסוים:
  1. קבועים סטטיים ציבוריים;
  2. קבועים סטטיים פרטיים;
  3. משתני מופע פרטי.
בהמשך יש בנאים שונים לפי סדר מפחות טיעונים ליותר. אחריהם עוקבות שיטות מגישה פתוחה יותר לסגורות ביותר: ככלל, שיטות פרטיות שמסתירות יישום של פונקציונליות כלשהי שאנו רוצים להגביל נמצאות בתחתית.

גודל כיתה

עכשיו אני רוצה לדבר על גודל הכיתה. כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 4בואו נזכור את אחד העקרונות של SOLID - אחריות יחידה . אחריות יחידה - עקרון האחריות היחידה. הוא קובע שלכל אובייקט יש רק מטרה אחת (אחריות), וההיגיון של כל השיטות שלו מכוון להבטיח זאת. כלומר, בהתבסס על זה, עלינו להימנע ממעמדות גדולים ונפוחים (שמטבעם הוא אנטי-תבנית - "אובייקט אלוהי"), ואם יש לנו הרבה שיטות של היגיון מגוון והטרוגני בכיתה, אנחנו צריכים לחשוב על פירוק זה לכמה חלקים לוגיים (מחלקות). זה, בתורו, ישפר את הקריאה של הקוד, מכיוון שאנחנו לא צריכים הרבה זמן כדי להבין את מטרת השיטה אם אנחנו יודעים את המטרה המשוערת של מחלקה נתונה. אתה גם צריך לפקוח עין על שם המחלקה : הוא צריך לשקף את ההיגיון שהוא מכיל. נניח, אם יש לנו מחלקה ששמה מכיל יותר מ-20 מילים, אנחנו צריכים לחשוב על refactoring. לכל כיתה שמכבדת את עצמה לא צריך להיות מספר כה גדול של משתנים פנימיים. למעשה, כל שיטה עובדת עם אחד מהם או עם כמה, מה שגורם לצימוד גדול יותר בתוך המחלקה (וזה בדיוק מה שהיא צריכה להיות, מכיוון שהמחלקה צריכה להיות כמכלול אחד). כתוצאה מכך, הגדלת הקוהרנטיות של כיתה מביאה לירידה בה ככזו, וכמובן, מספר הכיתות שלנו עולה. עבור חלק זה מעצבן; הם צריכים ללכת יותר לכיתה כדי לראות איך עובדת משימה גדולה ספציפית. בין היתר, כל מחלקה היא מודול קטן שאמור להיות מחובר באופן מינימלי לאחרות. בידוד זה מפחית את מספר השינויים שעלינו לבצע בעת הוספת לוגיקה נוספת למחלקה.

חפצים

כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 5

כימוס

כאן קודם כל נדבר על אחד העקרונות של OOP- encapsulation . לכן, הסתרת היישום אינה מסתכמת ביצירת שכבת שיטה בין משתנים (הגבלת גישה ללא מחשבה באמצעות שיטות בודדות, גטרים ו-seters, וזה לא טוב, שכן כל נקודת האנקפסולציה אובדת). הסתרת גישה מכוונת ליצירת הפשטות, כלומר, הכיתה מספקת שיטות קונקרטיות נפוצות דרכן אנו עובדים עם הנתונים שלנו. אבל המשתמש לא צריך לדעת איך בדיוק אנחנו עובדים עם הנתונים האלה - זה עובד, וזה בסדר.

חוק דמטר

אתה יכול גם לשקול את חוק דמטר: זהו סט קטן של כללים שעוזר לנהל מורכבות ברמת המחלקה והשיטה. אז בוא נניח שיש לנו אובייקט Carויש לו שיטה - move(Object arg1, Object arg2). על פי חוק דמטר, שיטה זו מוגבלת לקריאה:
  • שיטות של האובייקט עצמו Car(במילים אחרות, זה);
  • שיטות של אובייקטים שנוצרו ב move;
  • שיטות של אובייקטים שעברו כארגומנטים - arg1, arg2;
  • שיטות של אובייקטים פנימיים Car(אותו זה).
במילים אחרות, חוק דמטר הוא משהו כמו כלל ילדים - אתה יכול לדבר עם חברים, אבל לא עם זרים .

מבנה נתונים

מבנה נתונים הוא אוסף של אלמנטים קשורים. כאשר בוחנים אובייקט כמבנה נתונים, מדובר בקבוצה של רכיבי נתונים המעובדים בשיטות, שקיומם משתמע באופן מרומז. כלומר, מדובר באובייקט שמטרתו לאחסן ולתפעל (לעבד) נתונים מאוחסנים. ההבדל העיקרי מאובייקט רגיל הוא שאובייקט הוא קבוצה של שיטות הפועלות על רכיבי נתונים שקיומם משתמע. האם אתה מבין? באובייקט רגיל, ההיבט העיקרי הוא השיטות, ומשתנים פנימיים מכוונים לפעולתם הנכונה, אבל במבנה נתונים זה הפוך: שיטות תומכות ועוזרות לעבוד עם אלמנטים מאוחסנים, שהם העיקריים כאן. סוג אחד של מבנה נתונים הוא אובייקט העברת נתונים (DTO) . זוהי מחלקה עם משתנים ציבוריים וללא שיטות (או רק שיטות קריאה/כתיבה) המעבירות נתונים בעבודה עם מסדי נתונים, עבודה עם ניתוח הודעות משקעים וכו'. בדרך כלל, נתונים באובייקטים כאלה אינם מאוחסנים לאורך זמן והוא הומר כמעט מיד לישות שאיתה עובד האפליקציה שלנו. ישות, בתורה, היא גם מבנה נתונים, אך מטרתה להשתתף בלוגיקה עסקית ברמות שונות של האפליקציה, בעוד שה-DTO הוא להעביר נתונים אל/מ האפליקציה. DTO לדוגמה:
@Setter
@Getter
@NoArgsConstructor
public class UserDto {
    private long id;
    private String firstName;
    private String lastName;
    private String email;
    private String password;
}
הכל נראה ברור, אבל כאן אנו למדים על קיומם של כלאיים. כלאיים הם אובייקטים המכילים שיטות לטיפול בלוגיקה חשובה ולאחסן אלמנטים פנימיים ושיטות גישה (קבל/סט) אליהם. חפצים כאלה מבולגנים ומקשים על הוספת שיטות חדשות. אסור להשתמש בהם, שכן לא ברור למה הם מיועדים - אחסון אלמנטים או ביצוע היגיון כלשהו. על סוגי חפצים אפשריים תוכלו לקרוא כאן .

עקרונות יצירת משתנים

כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 6בואו נחשוב קצת על משתנים, או ליתר דיוק, נחשוב מה עשויים להיות העקרונות ליצירתם:
  1. באופן אידיאלי, עליך להצהיר ולאתחל משתנה מיד לפני השימוש בו (במקום ליצור אותו ולשכוח ממנו).
  2. במידת האפשר, הכריז על משתנים כסופיים כדי למנוע את שינוי ערכם לאחר האתחול.
  3. אל תשכח את משתני המונה (בדרך כלל אנו משתמשים בהם בלולאה כלשהי for, כלומר, אסור לשכוח לאפס אותם, אחרת זה יכול לשבור את כל ההיגיון שלנו).
  4. כדאי לנסות לאתחל משתנים בבנאי.
  5. אם יש בחירה בין שימוש באובייקט עם או בלי הפניה ( new SomeObject()), בחר ללא ( ), שכן אובייקט זה, לאחר השימוש בו, יימחק במהלך איסוף האשפה הבא ולא יבזבז משאבים.
  6. הפוך את משך החיים של המשתנים לקצר ככל האפשר (המרחק בין יצירת המשתנה לגישה האחרונה).
  7. אתחול משתנים המשמשים בלולאה מיד לפני הלולאה, במקום בתחילת השיטה המכילה את הלולאה.
  8. התחל תמיד עם ההיקף המצומצם ביותר והרחיב אותו רק במידת הצורך (כדאי לנסות להפוך את המשתנה לכמה שיותר מקומי).
  9. השתמש בכל משתנה למטרה אחת בלבד.
  10. הימנעו ממשתנים בעלי משמעויות נסתרות (המשתנה נקרע בין שתי משימות, כלומר הסוג שלו אינו מתאים לפתרון אחת מהן).
כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 7

שיטות

כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 8בואו נעבור ישירות ליישום ההיגיון שלנו, כלומר לשיטות.
  1. הכלל הראשון הוא קומפקטיות. באופן אידיאלי, שיטה אחת לא תעלה על 20 שורות, כך שאם, נניח, שיטה ציבורית "מתנפחת" באופן משמעותי, אתה צריך לחשוב על העברת ההיגיון המופרד לשיטות פרטיות.

  2. הכלל השני הוא שבלוקים בפקודות if, else, whileוכן הלאה לא צריכים להיות מקוננים במיוחד: זה מפחית משמעותית את הקריאות של הקוד. באופן אידיאלי, הקינון צריך להיות לא יותר משני בלוקים {}.

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

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

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

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

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

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

  7. אם למתודה יש ​​מספר רב של ארגומנטים נכנסים (הערך הקיצוני הוא 7, אבל אתה צריך לחשוב על זה אחרי 2-3), אתה צריך לקבץ כמה ארגומנטים באובייקט נפרד.

  8. אם יש כמה שיטות דומות (עמוסות יתר) , אז פרמטרים דומים חייבים לעבור באותו סדר: זה מגביר את הקריאות והשימושיות.

  9. כשאתה מעביר פרמטרים למתודה, אתה חייב להיות בטוח שבכולם ייעשה שימוש, אחרת בשביל מה הטיעון? חתוך את זה מהממשק וזהו.

  10. try/catchזה לא נראה מאוד יפה מטבעו, אז מהלך טוב יהיה להעביר אותו לשיטה נפרדת ביניים (שיטה לטיפול בחריגים):

    public void exceptionHandling(SomeObject obj) {
        try {
            someMethod(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
דיברתי על חזרה על קוד למעלה, אבל אוסיף אותו כאן: אם יש לנו כמה שיטות עם חלקים חוזרים של הקוד, אנחנו צריכים להעביר אותו לשיטה נפרדת, שתגדיל את הקומפקטיות של השיטה ושל הקוד. מעמד. ואל תשכח את השמות הנכונים. אני אספר לכם את הפרטים של השם הנכון של מחלקות, ממשקים, שיטות ומשתנים בחלק הבא של המאמר. וזה כל מה שיש לי להיום. כללים לכתיבת קוד: מיצירת מערכת ועד לעבודה עם אובייקטים - 9כללי קוד: כוחו של השם הנכון, הערות טובות ורעות
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION