כל מה שאתה צריך לדעת על עקרונות מוצקים בג'אווה

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

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



היסטוריה של עקרונות SOLID בג'אווה

רוברט סי מרטין נתן חמישה עקרונות עיצוב מונחים עצמים, וראשי התיבות 'S.O.L.I.D' משמשים אליו. כאשר אתה משתמש בכל העקרונות של S.O.L.I.D באופן משולב, קל לך יותר לפתח תוכנה שניתן לנהל בקלות. התכונות האחרות של שימוש ב- S.O.L.I.D הן:



  • זה נמנע מריחות קוד.
  • קוד רפרקטור במהירות.
  • יכול לעשות פיתוח תוכנה אדפטיבי או זריז.

כאשר אתה משתמש בעקרון של S.O.L.I.D בקידוד שלך, אתה מתחיל לכתוב את הקוד שהוא גם יעיל וגם יעיל.



מה הפירוש של S.O.L.I.D?

מוצק מייצג חמישה עקרונות של ג'אווה שהם:

  • ס : עקרון אחריות יחידה
  • אוֹ : עיקרון פתוח-סגור
  • ל : עיקרון החלפת ליסקוב
  • אני : עקרון הפרדת ממשק
  • ד : עקרון היפוך תלות

בבלוג זה נדון בפרטי כל חמשת עקרונות ה- SOLID של Java.



עקרון אחריות יחידה בג'אווה

מה זה אומר?

רוברט סי מרטין מתאר את זה שכיתה אחת צריכה להיות רק באחריות אחת ויחידה.

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

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

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

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

מדוע נדרש עקרון זה?

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

דוגמה להבהרת עקרון זה:

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

מחלקה ציבורית UserSettingService {public void changeEmail (משתמש משתמש) {if (checkAccess (user)) {// אפשרות הענפה לשינוי}} checkAccess בוליאני ציבורית (user user) {// ודא אם המשתמש חוקי. }}

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

מחלקה ציבורית UserSettingService {public void changeEmail (משתמש משתמש) {if (SecurityService.checkAccess (user)) {// אפשרות הענקה לשינוי}}} SecurityService בכיתה ציבורית {checkAccess בוליאני סטטי ציבורי (משתמש משתמש) {// לבדוק את הגישה. }}

פתח עקרון סגור בג'אווה

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

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

  • ירושה מהכיתה

  • החלפת ההתנהגויות הנדרשות מהכיתה

  • הרחבת התנהגויות מסוימות בכיתה

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

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

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

מדוע נדרש עקרון זה?

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

נניח שאנחנו צריכים לחשב שטחים בצורות שונות. אנו מתחילים ביצירת מחלקה למלבן הצורה הראשון שלנושיש לו 2 אורך תכונותורוחב.

מלבן בכיתה ציבורית {אורך כפול ציבורי ברוחב כפול ציבורי}

בשלב הבא אנו יוצרים מחלקה לחישוב השטח של מלבן זהשיש לו שיטה calcRectangleAreaשלוקח את המלבןכפרמטר קלט ומחשב את שטחו.

מחלקה ציבורית AreaCalculator {public double calculatorRectangleArea (מלבן מלבן) {return rectangle.length * rectangle.width}}

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

כיתת ציבור מעגל {רדיוס כפול ציבורי}

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

מחלקה ציבורית AreaCalculator {public double calculatorRectangleArea (מלבן מלבן) {return rectangle.length * rectangle.width} public double calcCircleArea (Circle Circle) {return (22/7) * circle.radius * circle.radius}}

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

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

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

שינוי התכנון לעיל כדי לעמוד בעקרון שנפתח / סגור:

הבה נראה כעת עיצוב אלגנטי יותר אשר פותר את הפגמים בעיצוב הנ'ל על ידי הקפדה על העיקרון הפתוח / סגור. קודם כל נעשה את העיצוב להרחבה. לשם כך עלינו להגדיר תחילה סוג בסיס Shape ולבצע ממשק צורה Circle & Rectangle.

ממשק ציבורי צורה {ציבורי כפול publicArea ()} מחלקה ציבורית מכלי מלבן צורה {אורך כפול רוחב כפול ציבורי ריבוי כפול () {אורך החזרה * רוחב}} מחלקה ציבורית מכשירים מעגל צורה {רדיוס כפול ציבורי ציבורי חישוב ציבורי () / 7) * רדיוס * רדיוס}}

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

מחלקה ציבורית AreaCalculator {ציבורי כפול publicShapeArea (צורת צורה) {return shape.calculateArea ()}}

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

עקרון החלפת ליסקוב בג'אווה

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

עקרון החלפת Liskov מניח ש- q (x) הוא מאפיין, הניתן להוכחה לגבי ישויות של x השייכות לסוג T. כעת, על פי עיקרון זה, q (y) אמור להיות מוכח כעת עבור אובייקטים y השייכים לסוג S, ו ה- S הוא למעשה תת-סוג של T. האם אתה מבולבל כעת ואינך יודע מה פירושו של עקרון החלפת ליסקוב? ההגדרה שלו עשויה להיות מעט מורכבת, אך למעשה היא די קלה. הדבר היחיד הוא שכל תת-מחלקה או מחלקה נגזרת צריכים להחליף את ההורה או את מחלקת הבסיס שלהם.

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

מדוע נדרש עקרון זה?

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

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

מלבן ציבורי מלבן {אורך int פרטי פרטי int רוחב public int getLength () {return length} public void setLength (int length) {this.length = length} public int getBreadth () {return width} public void setBreadth (int width) { this.breadth = width} public int getArea () {להחזיר this.length * this.breadth}}

להלן הקוד לריבוע. שים לב שריבוע מרחיב מלבן.

מחלקה ציבורית ריבוע משתרע מלבן {set set public setBreadth (int רוחב) {super.setBreadth (רוחב) super.setLength (רוחב)} set public space ריק (int אורך) {super.setLength (אורך) super.setBreadth (אורך)}}

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

מחלקה ציבורית LSPDemo {ציבור ריק מחשב שטח (מלבן r) {r.setBreadth (2) r.setLength (3) טוען r.getArea () == 6: printError ('אזור', r) טוען r.getLength () == 3: printError ('אורך', r) טוען r.getBreadth () == 2: printError ('רוחב', r)} מחרוזת פרטית printError (מחרוזת errorIdentifer, מלבן r) {להחזיר 'ערך לא צפוי של' + errorIdentifer + ' לדוגמא '+ r.getClass (). getName ()} ראשי ריק סטטי ציבורי (String [] args) {LSPDemo lsp = new LSPDemo () // מופע של מלבן מועבר lsp.calculateArea (מלבן חדש ()) // מופע של ריבוע מועבר lsp.calculateArea (ריבוע חדש ())}}

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

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

  1. אורך תמיד צריך להיות שווה לאורך שעבר כקלט לשיטה, setLength
  2. רוחב חייב להיות תמיד שווה לרוחב שהועבר כקלט לשיטה, setBreadth
  3. השטח חייב להיות תמיד שווה לתוצר של אורך ורוחב

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

הכיתה מרובעת אינה זקוקה לשיטות כמו setBreadth או setLength. מחלקת LSPDemo תצטרך לדעת את הפרטים של מחלקות נגזרות של מלבן (כגון ריבוע) כדי לקודד כראוי כדי למנוע שגיאת זריקה. השינוי בקוד הקיים שובר מלכתחילה את העיקרון הפתוח.

עקרון הפרדת ממשק

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

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

לדוגמא, ממשק רישום בודד לכתיבה ולקריאת יומנים שימושי למסד נתונים אך לא למסוף. קריאת יומנים אינה הגיונית עבור לוגר קונסולות. ממשיכים עם עקרונות ה- SOLID במאמר Java.

מדוע נדרש עקרון זה?

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

עכשיו בואו ניצור ממשק Java למסעדה ושמו בשם RestaurantInterface.java.

ממשק ציבורי RestaurantInterface {public void acceptOnlineOrder () public void takeTelephoneOrder () public void payOnline () public void walkInCustomerOrder () public public payInPerson ()}

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

נתחיל ביישום ה- RestaurantInterface עבור לקוחות מקוונים כ- OnlineClientImpl.java

מחלקה ציבורית OnlineClientImpl מיישם RestaurantInterface {public void acceptOnlineOrder () {// לוגיקה למתן הזמנה מקוונת} public void takeTelephoneOrder () {// לא ישמש להזמנה מקוונת זורק חדש UupportedOperationException ()} public public payOnline () {// לוגיקה לתשלום מקוון} walk void walkInCustomerOrder () {// לא רלוונטי להזמנה מקוונת לזרוק UnsupportedOperationException חדש ()} payInPerson חלל ציבורי () {// לא רלוונטי להזמנה מקוונת לזרוק UnsupportedOperationException חדש ()}}
  • מכיוון שהקוד שלעיל (OnlineClientImpl.java) מיועד להזמנות מקוונות, זרק UnsupportedOperationException.

  • לקוחות מקוונים, טלפוניים ותוספות משתמשים ביישום RestaurantInterface הספציפי לכל אחד מהם.

  • לשיעורי ההטמעה עבור לקוח טלפוני ולקוח Walk-in יהיו שיטות לא נתמכות.

  • מכיוון ש -5 השיטות הן חלק מ- RestaurantInterface, שיעורי ההטמעה צריכים ליישם את כל חמש השיטות.

  • השיטות שכל אחד משיעורי ההטמעה זורק UnsupportedOperationException. כפי שניתן לראות בבירור - יישום כל השיטות אינו יעיל.

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

    ליהוק ג'אווה כפול ל- int
  • RestaurantInterface.java מפר את עקרון האחריות היחידה מכיוון שההיגיון בתשלומים כמו גם בהזמנת ההזמנה מקובצים יחד בממשק יחיד.

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

  1. הפרד את פונקציות התשלום וההזמנות להזמין לשני ממשקים רזים נפרדים, PaymentInterface.java ו- OrderInterface.java.

  2. כל אחד מהלקוחות משתמש ביישום אחד של PaymentInterface ו- OrderInterface. לדוגמא - OnlineClient.java משתמש ב- OnlinePaymentImpl וב- OnlineOrderImpl וכן הלאה.

  3. עקרון האחריות היחידה מצורף כעת כממשק תשלום (PaymentInterface.java) וממשק הזמנות (OrderInterface).

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

לאחר החלת ספק שירותי האינטרנט

עקרון היפוך תלות

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

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

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

מדוע נדרש עקרון זה?

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

כיתה ציבורית סטודנט {כתובת כתובת פרטית סטודנט ציבורי () {כתובת = כתובת חדשה ()}}

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

בכך אנו מגיעים לקצה של עקרונות ה- SOLID הללו בג'אווה.

בדוק את מאת אדוריקה, חברת למידה מקוונת מהימנה עם רשת של יותר מ -250,000 לומדים מרוצים הפזורים ברחבי העולם. קורס ההכשרה וההסמכה של Java J2EE ו- SOA של אדוריקה מיועד לסטודנטים ואנשי מקצוע שרוצים להיות מפתח Java. הקורס נועד לתת לך יתרון בתכנות ג'אווה ולהכשיר אותך למושגי ג'אווה מרכזיים ומתקדמים יחד עם מסגרות ג'אווה שונות כמו Hibernate & Spring.

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