תבנית Builder
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 67 מתוך 87.
תבנית הבנאי היא תבנית עיצוב ליצירה שפותרת בעיה נפוצה: בניית אובייקטים מורכבים עם פרמטרים אופציונליים רבים. במקום ליצור כמה בנאים או להעביר null עבור פרמטרים שאינם בשימוש, הבנאי מאפשר לך לבנות אובייקטים שלב אחר שלב.
שקלו ליצור אובייקט User עם שדות חובה (שם, דוא״ל) ושדות אופציונליים (גיל, טלפון, כתובת). בלי Builder, תצטרכו להשתמש בבנאים מדורגים או בבנאי מסורבל עם פרמטרים רבים. תבנית Builder מציעה גישה נקייה יותר:
public class User {
private final String name; // חובה
private final String email; // חובה
private final int age; // לא חובה
private final String phone; // לא חובה
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}השיטות של הבנאי מחזירות את this, וכך מאפשרות שרשור שיטות: דרך זורמת וקריאה לבניית אובייקטים:
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();שימו לב שבנאי של User הוא פרטי: אפשר ליצור אובייקטים רק באמצעות ה־Builder. דפוס זה מצטיין כשלאובייקטים יש שדות אופציונליים רבים, והופך את הקוד לקריא יותר ולמועד פחות לשגיאות מאשר רשימות ארוכות של פרמטרים.
אתגר
קלבואו נבנה מערכת להזמנת פיצות באמצעות תבנית Builder! במקום להתמודד עם בנאי שמקבל עשרות פרמטרים עבור כל התוספות והאפשרויות האפשריות, תיצרו builder גמיש שמאפשר להתאים אישית פיצה בצורה נקייה וקריאה.
תארגנו את הקוד שלכם בשני קבצים:
Pizza.java: צרו מחלקהPizzaשמשתמשת בתבנית Builder ליצירת אובייקטים. לפיצה שלכם צריכים להיות השדות הבאים:size(String) - חובה, מייצג את גודל הפיצהcheese(boolean) - אופציונלי, ברירת המחדל היא falsepepperoni(boolean) - אופציונלי, ברירת המחדל היא falsemushrooms(boolean) - אופציונלי, ברירת המחדל היא falseהבנאי של
Pizzaצריך להיות private ולקבל רקPizzaBuilderכפרמטר, ולהעתיק את כל הערכים מה-builder לשדות של הפיצה.כללו מתודה
getDescription()שמחזירה מחרוזת בפורמט הזה:[size] Pizza with: [toppings], כאשר התוספות הן רשימה מופרדת בפסיקים של התוספות שערכן true (Cheese, Pepperoni, Mushrooms). אם לא נבחרו תוספות, החלק של התוספות צריך להכיל רק אתno toppings.צרו מחלקה פנימית סטטית
PizzaBuilderעם:- בנאי שמקבל את הפרמטר הנדרש
size - מתודות
cheese(),pepperoni()ו-mushrooms(), שכל אחת מהן מגדירה את הערך הבוליאני המתאים ל-true ומחזירה אתthisכדי לאפשר שרשור - מתודה
build()שמחזירהPizzaחדשה
- בנאי שמקבל את הפרמטר הנדרש
Main.java: הדגימו את פעולת ה-builder של הפיצה שלכם! תקבלו ארבעה קלטים: גודל הפיצה (String) ושלושה ערכי כן/לא (Strings) המציינים אם להוסיף גבינה, פפרוני ופטריות, בהתאמה.צרו
PizzaBuilderעם הגודל הנתון. לאחר מכן, בהתאם לכל קלט כן/לא, שרשרו את המתודות המתאימות להוספת התוספות. אם הקלט הוא"yes", קראו למתודה של אותה תוספת; אם הוא"no", דלגו עליה. לבסוף, קראו ל-build()כדי ליצור את הפיצה.הדפיסו את התוצאה של קריאה ל-
getDescription()על הפיצה שיצרתם.
תקבלו ארבעה קלטים לפי הסדר הבא: גודל (String), הוספת גבינה (String: "yes" או "no"), הוספת פפרוני (String: "yes" או "no"), הוספת פטריות (String: "yes" או "no").
לדוגמה, עבור הקלטים Large, yes, no, yes, הפלט שלכם יהיה: Large Pizza with: Cheese, Mushrooms
שימו לב כיצד תבנית Builder מאפשרת לכם ליצור פיצות עם כל שילוב של תוספות, בלי צורך בבנאים נפרדים לכל אפשרות!
נסו בעצמכם
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// קרא את הקלטים
String size = scanner.nextLine();
String addCheese = scanner.nextLine();
String addPepperoni = scanner.nextLine();
String addMushrooms = scanner.nextLine();
// TODO: צור PizzaBuilder בגודל הנתון
// TODO: שרשר את המתודות להוספת תוספות בהתאם לקלטים של yes/no
// TODO: בנה את הפיצה והדפס את התיאור שלה
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותשדות (מאפיינים)מתודת הבנאיהעמסת בנאיםחזרה – מחשבון פשוט4ירושה
ירושה בסיסית (extends)מילת המפתח superדריסת מתודות (@Override)שרשור בנאיםהמחלקה Objectירושה יחידה ורב־רמתיתלמה אין ירושה מרובה של מחלקותסיכום – היררכיית עובדים7מתודות מיוחדות ומחלקת Object
מתודת toString()equals() ו-hashCode()מתודת clone()compareTo() ו-Comparableהממשק Comparatorסיכום – מיון מותאם אישית2מצייני גישה ואנקפסולציה
סקירה של רמות הגישהמתודות Getter ו-Setterהסתרת מידעמילת המפתח finalסיכום – מנהל חשבון בנק5פולימורפיזם
יסודות העמסת מתודותדריסת מתודות (בזמן ריצה)המרה כלפי מעלה וכלפי מטההאופרטור instanceofמחלקות ומתודות מופשטותסיכום – מחשבון צורות8מושגי OOP מתקדמים
הרכבה מול ירושהאגרגציה מול הרכבהמחלקות פנימיות, מקוננות ואנונימיותEnums ומתודות של EnumRecords (Java 16+)מחלקות חתומות (Java 17+)11תבניות עיצוב חלק 1
מבוא לתבניות עיצובתבנית Singletonתבנית Factoryתבנית Builderתבנית Observerתבנית Strategy3מאפייני מחלקה וחברים סטטיים
משתני מופע לעומת משתנים סטטייםמתודות סטטיותבלוקים סטטייםקבועים (static final)סיכום — מונה ומחלקת עזר6ממשקים ומחלקות מופשטות
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםמתודות ברירת מחדל וסטטיות בממשקמחלקות מופשטות לעומת ממשקיםממשקים פונקציונלייםסיכום – מערכת תשלומיםתרגלו בעצמכם: קומפיילר Java אונליין