תבנית Strategy
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Dart של Coddy. שיעור 93 מתוך 110.
תבנית Strategy מאפשרת לך להגדיר משפחה של אלגוריתמים, לעטוף כל אחד מהם במחלקה משלו ולהפוך אותם לניתנים להחלפה בזמן ריצה. במקום לקבע את ההתנהגות בתוך מחלקה, מזריקים את ההתנהגות באמצעות ממשק, וכך אפשר להחליף אסטרטגיות בלי לשנות את המחלקה שמשתמשת בהן.
נבחן מערכת תשלומים שבה רוצים לתמוך באמצעי תשלום שונים. במקום להשתמש בתנאים כדי לטפל בכל אמצעי, מגדירים ממשק אסטרטגיה ויוצרים מימושים קונקרטיים:
abstract class PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
@override
void pay(double amount) => print('Paid \$$amount with Credit Card');
}
class PayPalPayment implements PaymentStrategy {
@override
void pay(double amount) => print('Paid \$$amount with PayPal');
}
class ShoppingCart {
PaymentStrategy _paymentStrategy;
ShoppingCart(this._paymentStrategy);
void setPaymentStrategy(PaymentStrategy strategy) {
_paymentStrategy = strategy;
}
void checkout(double total) {
_paymentStrategy.pay(total);
}
}
void main() {
var cart = ShoppingCart(CreditCardPayment());
cart.checkout(99.99); // שולם $99.99 בכרטיס אשראי
cart.setPaymentStrategy(PayPalPayment());
cart.checkout(49.99); // שולם $49.99 באמצעות PayPal
}ShoppingCart לא יודע ולא אכפת לו איך התשלום מתבצע — הוא פשוט מעביר את הטיפול לאסטרטגיה שמוגדרת כרגע. אפשר להוסיף אמצעי תשלום חדשים באמצעות יצירת מחלקות אסטרטגיה חדשות, בלי לגעת בקוד של העגלה. התבנית הזאת אידיאלית כשיש כמה דרכים לבצע פעולה ורוצים לבחור ביניהן או לעבור ביניהן באופן דינמי.
אתגר
קלבואו נבנה מערכת לעיצוב טקסט באמצעות תבנית האסטרטגיה! תיצרו מערכת שבה ניתן להחיל אסטרטגיות עיצוב שונות על טקסט, ולאפשר למשתמשים לעבור בין פורמטים באופן דינמי בלי לשנות את מעבד הטקסט המרכזי.
תארגנו את הקוד שלכם בשני קבצים:
formatting_strategies.dart: צרו כאן את מערכת האסטרטגיות. הגדירו מחלקה מופשטתFormattingStrategyעם מתודהString format(String text). לאחר מכן ממשו שלוש אסטרטגיות קונקרטיות:UppercaseStrategy- ממירה את הטקסט כולו לאותיות גדולותLowercaseStrategy- ממירה את הטקסט כולו לאותיות קטנותTitleCaseStrategy- הופכת את האות הראשונה בכל מילה לאות גדולה (פיצול לפי רווחים, הפיכת התו הראשון בכל מילה לאות גדולה ושאר האותיות לקטנות)
TextProcessorשמחזיקהFormattingStrategy. צריכה להיות לה בנאית שמקבלת אסטרטגיה התחלתית, מתודהsetStrategy()לשינוי האסטרטגיה בזמן הריצה, ומתודהprocess(String text)שמחילה את האסטרטגיה הנוכחית ומחזירה את התוצאה המעוצבת.main.dart: ייבאו את אסטרטגיות העיצוב שלכם והדגימו כיצד תבנית האסטרטגיה מאפשרת מעבר דינמי בין התנהגויות. צרוTextProcessorשמתחיל עםUppercaseStrategy. עבדו את הטקסטhello worldוהדפיסו את התוצאה. לאחר מכן עברו ל־LowercaseStrategy, עבדו אתHELLO WORLDוהדפיסו. לבסוף, עברו ל־TitleCaseStrategy, עבדו אתthe quick brown foxוהדפיסו את התוצאה.
הדבר מדגים את העוצמה של תבנית האסטרטגיה — TextProcessor לא צריך לדעת את הפרטים של אופן פעולת העיצוב. הוא פשוט מעביר את העבודה לאסטרטגיה שמוגדרת כרגע, וכך קל להוסיף אפשרויות עיצוב חדשות בלי לשנות את המעבד!
הפלט הצפוי:
HELLO WORLD
hello world
The Quick Brown Foxנסו בעצמכם
import 'formatting_strategies.dart';
void main() {
// TODO: צרו TextProcessor שמתחיל עם UppercaseStrategy
// TODO: עבדו את הטקסט 'hello world' והדפיסו את התוצאה
// TODO: עברו ל-LowercaseStrategy
// TODO: עבדו את 'HELLO WORLD' והדפיסו את התוצאה
// TODO: עברו ל-TitleCaseStrategy
// TODO: עבדו את 'the quick brown fox' והדפיסו את התוצאה
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםספריות וייבואמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותמשתני מופעיסודות הבנאיחזרה: מחשבון פשוט4בטיחות מפני ערכי null
מבוא לבטיחות מפני ערכי nullניתן להקצאה ל-null לעומת לא ניתן להקצאה ל-nullהאופרטורים ? ו-!מילת המפתח Late ובטיחות מפני ערכי nullאופרטורים מודעי nullבטיחות מפני ערכי null במחלקותסיכום – מערכת פרופילי משתמשים7מחלקות מופשטות וממשקים
מחלקות מופשטותמתודות מופשטותממשקים ב-Dartממשקים משתמעיםמימוש לעומת הורשהממשקים מרוביםחזרה – מחשבון צורות10אוספים וגנריות
סקירה כללית של List, Set ו-Mapאוספים בטוחים מבחינת טיפוסיםמחלקות גנריותמתודות גנריותאילוצים גנרייםIterable ו-Iteratorסיכום – אחסון גנרי13מושגי OOP מתקדמים
הרכבה לעומת הורשהמתודות הרחבהמחלקות קריאותמחלקות אטומות (Dart 3)רשומות (Dart 3)תבניות והתאמה (3.0)טיפוסים מונים עם מתודות16פרויקט: ניהול ספרייה
סקירת הפרויקטמחלקות ספר ומשתמש2בנאים ב-Dart
בנאי ברירת מחדלבנאים בעלי שםרשימות אתחולבנאים קבועיםבנאי Factoryבנאים מפניםסיכום - בונה צורות5כימוס
חברים ציבוריים לעומת פרטייםמוסכמת הקידומת _פרטיות ברמת הספרייההעמקה ב-getters וב-settersהסתרת מידעסיכום – רשומות תלמידים8מיקסינים
מבוא למיקסיניםיצירת מיקסיניםשימוש במספר מיקסיניםמילת המפתח on במיקסיניםמיקסינים לעומת ירושהמיקסינים לעומת ממשקסיכום – מערכת בעלי החיים3מאפייני מחלקה
איברי מופע לעומת איברים סטטייםשדות final ו-constמשתני lateמתודות ושדות סטטייםGetters ו-Settersסיכום – מנהל חשבונות בנק6ירושה
ירושה בסיסיתמילת המפתח superדריסת מתודותהאנוטציה @overrideמילת המפתח final למחלקהבנאים וירושהסיכום – היררכיית עובדים9פולימורפיזם
יסודות הפולימורפיזםפולימורפיזם באמצעות ממשקיםבדיקת טיפוסים בזמן ריצההאופרטורים is ו-asמילת המפתח קווריאנטיסיכום — מעבד תשלומים12תכנות מונחה עצמים אסינכרוני
Future-ים ו-async/awaitיסודות ה-Streamsבקרי Streamsבנאים אסינכרונייםאסינכרוניות במתודות של מחלקהסיכום - אחזור נתוניםתרגלו בעצמכם: קומפיילר Dart אונליין