JavaRush /בלוג Java /Random-HE /עקרונות OOP

עקרונות OOP

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

עקרונות בסיסיים של OOP:

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

מהו חפץ?

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

OOP הפשטה

כעת נחשוב כיצד אנו יכולים לעבור מאובייקט בעולם האמיתי לאובייקט בתוכנית, באמצעות הטלפון כדוגמה. ההיסטוריה של אמצעי תקשורת זה עולה על 100 שנים והטלפון המודרני, בניגוד לקודמו מהמאה ה-19, הוא מכשיר מורכב הרבה יותר. כשאנחנו משתמשים בטלפון, אנחנו לא חושבים על המבנה שלו ועל התהליכים המתרחשים בתוכו. אנחנו פשוט משתמשים בפונקציות שמספקות מפתחי הטלפון - כפתורים או מסך מגע כדי לבחור מספר ולבצע שיחות. אחד ממשקי הטלפון הראשונים היה כפתור שסובבתם כדי לבצע שיחה. כמובן שזה לא היה נוח במיוחד. עם זאת, הידית ביצעה את תפקידה כראוי. אם מסתכלים על הטלפון הכי מודרני והראשון, אפשר לזהות מיד את הפרטים הכי חשובים שחשובים גם למכשיר מסוף המאה ה-19 וגם לסמארטפון אולטרה מודרני. זה ביצוע שיחה (חיוג למספר) וקבלת שיחה. בעיקרו של דבר, זה מה שהופך טלפון לטלפון ולא למשהו אחר. כעת יישמנו את העיקרון ב-OOP - הדגשת המאפיינים והמידע החשובים ביותר על אובייקט. עקרון זה של OOP נקרא הפשטה. הפשטה ב-OOP יכולה להיות מוגדרת גם כדרך לייצוג אלמנטים של בעיה בעולם האמיתי כאובייקטים בתוכנית. הפשטה תמיד קשורה להכללה של מידע כלשהו על מאפיינים של אובייקטים או אובייקטים, ולכן העיקר הוא להפריד מידע משמעותי ממידע לא משמעותי בהקשר של הבעיה הנפתרת. במקרה זה, יכולות להיות מספר רמות של הפשטה. בואו ננסה ליישם את עקרון ההפשטה על הטלפונים שלנו. ראשית, בואו נדגיש את סוגי הטלפונים הנפוצים ביותר מהראשון ועד היום. לדוגמה, ניתן לייצג אותם בצורה של דיאגרמה המוצגת באיור 1. עקרונות OOP - 2כעת, בעזרת הפשטה, נוכל להדגיש מידע כללי בהיררכיה זו של אובייקטים: סוג מופשט נפוץ של אובייקטים - טלפון, מאפיין כללי של אובייקטים. הטלפון - שנת יצירתו, וממשק משותף - כל הטלפונים מסוגלים לקבל ולשלוח שיחות. כך זה נראה ב-Java:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outputNumber);
    public abstract void ring (int inputNumber);
}
בהתבסס על מחלקה מופשטת זו, נוכל ליצור סוגים חדשים של טלפונים בתוכנית תוך שימוש בעקרונות בסיסיים אחרים של Java OOP, אותם נשקול להלן.

כימוס

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

אנקפסולציה ובקרת גישה

נניח שבמהלך הייצור, מידע אודותיו נחרט בגב הטלפון: שנת הייצור שלו או הלוגו של חברת היצרן. מידע זה מאפיין באופן די ספציפי את הדגם הזה - מצבו. אנו יכולים לומר שמפתח הטלפון דאג לבלתי משתנה של המידע הזה - לא סביר שמישהו יחשוב להסיר את החריטה. בעולם הג'אווה, מצבם של אובייקטים עתידיים מתואר במחלקה באמצעות שדות, והתנהגותם מתוארת באמצעות מתודות. היכולת לשנות מצב והתנהגות מתבצעת באמצעות משנה גישה לשדות ושיטות - private, protected, publicו- default(גישה ברירת מחדל). לדוגמה, החלטנו ששנת היצירה, שם יצרן הטלפון ואחת השיטות שייכים ליישום הפנימי של המחלקה ואינן ניתנות לשינוי על ידי אובייקטים אחרים בתוכנית. באמצעות קוד, ניתן לתאר את המחלקה באופן הבא:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    //findComutator
    //openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("I'm calling a number");
}

public void ring() {
    System.out.println("Дзынь-дзынь");
}

 }
משנה privateהופך את השדות והשיטות של מחלקה לזמינים רק בתוך אותה מחלקה. המשמעות היא privateשלא ניתן לגשת לשדות מבחוץ, וגם לא ניתן privateלקרוא לשיטות. הסתרת גישה לשיטה openConnectionמותירה לנו גם את ההזדמנות לשנות באופן חופשי את היישום הפנימי של שיטה זו, שכן מובטח שיטה זו לא תשמש אובייקטים אחרים ולא תשבש את פעולתם. כדי לעבוד עם האובייקט שלנו, אנו משאירים את השיטות פתוחות callבאמצעות ringה-modifier public. מתן שיטות ציבוריות לעבודה עם אובייקט הוא גם חלק ממנגנון האנקפסולציה, שכן אם הגישה לאובייקט תישלל לחלוטין, הוא יהפוך לחסר תועלת.

יְרוּשָׁה

בואו נסתכל שוב על טבלת הטלפון. ניתן לראות שהוא מייצג היררכיה שבה למודל הממוקם למטה יש את כל המאפיינים של הדגמים הממוקמים גבוה יותר בסניף, פלוס משלו. למשל, סמארטפון משתמש ברשת סלולרית לתקשורת (בעל תכונות של טלפון סלולרי), הוא אלחוטי ונייד (בעל תכונות של טלפון אלחוטי), ויכול לקבל ולבצע שיחות (בעל תכונות של טלפון). במקרה זה, אנו יכולים לדבר על ירושה של מאפייני אובייקט. בתכנות, ירושה היא השימוש במחלקות קיימות כדי להגדיר מחלקות חדשות. בואו נסתכל על דוגמה ליצירת מחלקה לסמארטפון באמצעות ירושה. כל הטלפונים האלחוטיים מופעלים על ידי סוללות נטענות, בעלות חיי פעולה מסוימים בשעות. אז בואו נוסיף את המאפיין הזה למחלקה של טלפונים אלחוטיים:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
callטלפונים סלולריים יורשים את המאפיינים של טלפון אלחוטי, הוספנו גם יישום של שיטות ו למחלקה זו ring:
public class CellPhone extends WirelessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("Calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("A subscriber is calling you" + inputNumber);
    }
}
ולבסוף, מחלקת הסמארטפונים, שבניגוד לטלפונים סלולריים קלאסיים, יש לה מערכת הפעלה מלאה. אתה יכול להוסיף תוכניות חדשות הנתמכות על ידי מערכת הפעלה זו לסמארטפון שלך, ובכך להרחיב את הפונקציונליות שלו. באמצעות קוד, ניתן לתאר את המחלקה באופן הבא:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program){
    System.out.println("Installing" + program + "For" + operationSystem);
}

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

רב צורתיות

אם נסתכל על כל דגמי הטלפונים, אזי, למרות ההבדלים במראה ובעיצוב של הדגמים, נוכל לזהות בהם כמה התנהגות נפוצה – כולם יכולים לקבל ולבצע שיחות ויש להם סט די ברור ופשוט של כפתורי שליטה. תוך יישום אחד העקרונות הבסיסיים של OOP, המוכר לנו כבר, הפשטה במונחי תכנות, אנו יכולים לומר שלאובייקט הטלפון יש ממשק אחד משותף. לכן, משתמשי טלפון יכולים להשתמש בדגמים שונים בצורה נוחה באמצעות אותם לחצני שליטה (מכני או מגע), מבלי להיכנס לפרטים הטכניים של המכשיר. אז, אתה כל הזמן משתמש בטלפון סלולרי, ואתה יכול בקלות לבצע שיחה מעמיתו הקווי. העיקרון ב-OOP כאשר תוכנית יכולה להשתמש באובייקטים עם אותו ממשק ללא מידע על המבנה הפנימי של האובייקט נקרא פולימורפיזם . בואו נדמיין שבתוכנית שלנו אנחנו צריכים לתאר משתמש שיכול להשתמש בכל דגם טלפון כדי להתקשר למשתמש אחר. הנה איך לעשות את זה:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// here it is polymorphism - using the abstract type AbstractPhone phone in the code!
        phone.call(number);
    }
}
 }
כעת נתאר את דגמי הטלפון השונים. אחד מדגמי הטלפון הראשונים:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outputNumber) {
        System.out.println("Turn the Handle");
        System.out.println("Give me the phone number, sir");
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
טלפון קווי רגיל:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("I'm calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
ולבסוף, טלפון וידאו מגניב:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outputNumber) {
        System.out.println("I connect a video channel for the subscriber" + outputNumber );
    }
    @Override
    public void ring(int inputNumber) {
        System.out.println("You have an incoming video call..." + inputNumber);
    }
  }
בואו ניצור אובייקטים בשיטה main()ונבדוק את השיטה callAnotherUser:
AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Andrey");
user.callAnotherUser(224466,firstPhone);
// Rotate the knob
// Tell me the number of the subscriber, sir
user.callAnotherUser(224466,phone);
//Call number 224466
user.callAnotherUser(224466,videoPhone);
//I connect the video channel for subscriber 224466
על ידי קריאה לאותה שיטה על האובייקט user, קיבלנו תוצאות שונות. הבחירה ביישום שיטה ספציפית callבתוך שיטה callAnotherUserנעשתה באופן דינמי על סמך הסוג הספציפי של האובייקט הקורא במהלך ביצוע התוכנית. זהו היתרון העיקרי של פולימורפיזם - בחירת היישום במהלך ביצוע התוכנית. בדוגמאות של מחלקות הטלפון לעיל, השתמשנו ב- method overriding, טכניקה המשנה את יישום השיטה המוגדרת במחלקה הבסיסית מבלי לשנות את חתימת השיטה. זוהי בעצם החלפת שיטה, וזו השיטה החדשה המוגדרת בתת-המחלקה שנקראת כאשר התוכנית פועלת. בדרך כלל, בעת עקיפת שיטה, נעשה שימוש בהערה @Override, שאומר למהדר לבדוק את החתימות של השיטות הנעקפות והדרסות. כתוצאה מכך , כדי להבטיח שהסגנון של התוכנית שלך תואם את הרעיון של OOP ולעקרונות של OOP Java, פעל לפי הטיפים הבאים:
  • להדגיש את המאפיינים העיקריים של האובייקט;
  • להדגיש מאפיינים והתנהגות נפוצים ולהשתמש בירושה בעת יצירת אובייקטים;
  • להשתמש בסוגים מופשטים לתיאור אובייקטים;
  • נסו תמיד להסתיר שיטות ושדות הקשורים ליישום הפנימי של המחלקה.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION