Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns...

30
Design Patterns 4 Design Patterns מאיר סלע2004 מהדורה ראשונה1 הדפסה כל הזכויות שמורות2000 עיט מרכז ההדרכהwww.mh2000.co.il אתר אינטרנט:[email protected] דואר אלקטרוני: אמצעי אלקטרוני, צורה ובשו ממנו, בשו ספר זה או קטעי להעתיק, לשכפל או לצל אי אופטי או מכני לכל מטרה שהיא, ללא אישור בכתב מההוצאה לאור.

Transcript of Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns...

Page 1: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 4

Design Patternsמאיר סלע

מהדורה ראשונה 2004

הדפסה 1

כל הזכויות שמורות

מרכז ההדרכה עיט� 2000

www.mh2000.co.il :אתר אינטרנט

[email protected] :דואר אלקטרוני

אי� להעתיק, לשכפל או לצל� ספר זה או קטעי� ממנו, בשו� צורה ובשו� אמצעי אלקטרוני,

אופטי או מכני לכל מטרה שהיא, ללא אישור בכתב מההוצאה לאור.

Page 2: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק 1 : מבוא 13

1 . מבוא

נושאי הפרק:

• Design Patterns � הגדרה, מאפייני, יישו

• מדדי בפיתוח תוכנה � וכיצד Design Patterns מסייעי בהשגת

• Reference � מקורות ספרות

Page 3: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 14

Design Patterns

design patterns הוא תחו� במסגרת הכללית של תיכו מונחה עצמי� (Object Oriented Design), הכולל טכניקות תיכו� ותכנות מתקדמות.

המקור התיעודי העיקרי ל� patterns הוא הספר[Gamma95]. לספר ארבעה מחברי�, ולכ� ה�

מכוני� לפעמי� בקיצור ג� Gang Of Four � GOF. מחברי הספר עצמ� מעידי� שמקור

ההשראה העיקרי עבור� היה ספרו של כריסטופר אלכסנדר [Alexander79] שעסק בתכנו�

וארכיטקטורה אורבניי�.

בספר זה נסקור את ה� patterns התקניי� והמוכרי� בתעשיית התוכנה. לכל pattern נית� ש�

מזהה ותיאור בשלושה חלקי�:

− תיאור הקשר (context) הבעיה תו� התבוננות בדוגמא

.C++/Java/C# כמו ג� קוד דוגמא ב� ,UML תיאור הפתרו� בצורת תרשי� תיכו� −

− הכללת הפתרו� למקרה הכללי תו� ציו� קשרי� ע� patterns אחרי�, וריאציות שונות

של הפתרו�, השלכות, ושימושי� לדוגמא.

כפי שנאמר, המקור העיקרי ל� patterns הוא הספר [Gamma95]. עקב גילו, שפת התרשימי�

שבו אינה עדכנית (לא UML), מערכות העצמי� ודוגמאות הקוד שבו מיושנות. ספר זה עושה

שימוש בתרשימי UML, כולל עדכוני� רבי�, תוספות ודוגמאות ממערכות עצמי� מודרניות.

Design Pattern � מה זה?

קיימות מספר הגדרות ל� design pattern, אול� הדר� הבהירה ביותר להבנתו היא באמצעות

מאפייניו. pattern מצוי :

• מספק פתרו� לבעיה כללית החוזרת ומופיעה בצורות שונות

• יכול לכלול מספר וריאציות של הפתרו� (בהתא� לוריאציות של הבעיה ולשיקולי תיכנו�

נוספי�)

• נבדק ונוסה כבר פעמי� רבות (בהצלחה)

• בד"כ מתייחס לתחושת dejavu של מפתחי� מנוסי� בהקשר הנתו�

• לרוב ממומש ע"י שיתו� פעולה בי� מספר מחלקות/עצמי�

• לרוב הוא אינו המצאה או גילוי של אד� מסויי�

Page 4: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק 1 : מבוא 15

:GOF הגדרה של מחברי הספר

Design Patterns - “Descriptions of communicating objects and classes that arecustomized to solve a general design problem in a particular context.”

: [Alexander79] הגדרה של אלכסנדר בספרו

“Each pattern is a three-part rule, which expresses a relation between a certaincontext, a problem, and a solution.“

patterns מטרות בלימוד ה�

המטרות העיקריות בלימוד ה� patterns שבספר זה ה�:

• הכרה וזיהוי של תבניות בעיות ופתרונ� � בכדי לזהות pattern ראשית יש להכירו, ולהפני�

את המבנה שלו, כמו ג� את שמו. לא תמיד קל לזהות patterns, אול� הזמ� והתרגול

מסייעי� בכ�.

patterns רכישת שפה "גבוהה" לביטוי ולתיעוד התבניות הנ"ל � לאחר תהלי� ההפנמה של ה� •

נית� לקטו� פירות נוספי�: קיבלנו שפת patterns שנית� להשתמש בה במסגרת תיכו�, ייעו�,

שיחה, תיעוד ולימוד.

לדוגמא, במקו� לכתוב בתיעוד מחלקה מסויימת בתכנית שהגדרת את ה� constructor כ�

protected בכדי למנוע ייצור מפורש של עצמי� מהמחלקה, א� סיפקת פונקציה סטטית לקבלת המופע היחיד שלו, אתה יכול להשתמש במילה אחת השקולה לתיאור הנ"ל:

.Singleton

• לימוד מניסיונ� של אחרי� בנושאי תיכו� ותכנות � ה� patterns ה� למעשה מאגר של הידוע

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

רבי� וטובי�, והצגת הידע הזה כקטלוג של טכניקות תכנות מקצרת את תהלי� הלימוד של

.OO ה"תורה שבעל�פה" עבור מהנדסי תוכנה פחות מנוסי� ב�

תוצרי לוואי:

• לימוד ותרגול UML כשפה לתיאור מודלי תוכנה � מרבית הדיוני� שבספר זה מתבצעי�

ברמת התיכו� ב� UML, כאשר פה וש� מובאות דוגמאות קוד. אחת התוצאות של לימוד ה�

patterns היא הכרת UML בצורה מחודדת ומעמיקה.

patterns התנסות בתיכו� ובמעבר מתיכו� למימוש � שיקולי התיכו� שמלווי� חלק גדול מה� •

מספקי� התנסות עשירה בבחינת השפעת� במעבר למימוש.

Page 5: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 16

• הכרה והתנסות ע� מנגנוני� מתקדמי� ב� OOP: פולימורפיז� ופולימורפיז� טהור,

.RTTI ,templates / Generics

C# ,Java ,C++ בספר מובאות דוגמאות בשפות �חשיפה למערכות עצמי� מתקדמות •

ובמערכות MFC, .NET, Java, COM. ה� patterns עוזרי� להבי� בקלות ובמהירות מערכות

וספריות מורכבות מאוד.

מדדי בפיתוח תוכנה

המטרה המשותפת לכל ה� patterns שבספר זה היא פיתוח תוכנה "טובה" יותר. השאלה

הראשונה שעולה מכא� היא "מהי תוכנה טובה יותר?" � לש� כ� קיימי� מספר מדדי� מקובלי�

להערכת תוכנה:

• גמישות � היכולת לבצע שינויי� בתוכנה ללא מאמ� רב.

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

• יעילות � ניצול משאבי מקו� וזמ� שצורכי� מרכיבי המערכת.

• בהירות � היכולת ללמוד את המערכת ללא מאמ� רב ובזמ� קצר.

• ניידות � יכולת הסבה של התוכנה לספריות, מערכות ומחשבי� שוני�.

במילי� אחרות, תוכנה היא טובה יותר ככל שהיא יעילה יותר, גמישה יותר בפני ביצוע שינויי�,

מאפשרת תוספות בצורה קלה ופשוטה יותר וככל שנית� להסב אותה לסביבות שונות ביתר

קלות.

מדד אחר שמקובל להגדיר באופ� כללי הוא פשטות, והוא כולל בתוכו את כל המדדי� האחרי�:

ככל שהמערכת פשוטה וטבעית יותר, היא מובנת יותר, נוחה יותר להרחבה ולשינוי ולכ� טובה

."Keep It Simple" לביטוי KIS יותר. באנגלית קיי� קיצור

מדדי� פרטניי� יותר

השאלה: כיצד בוני� תוכנה שתענה לדרישות הנ"ל � יעילה, בעלת יכולת גמישות, יכולת הרחבה

ויכולת נייוד טובות יותר?בכדי לענות לשאלה, עלינו לפרוט את המדדי� הנ"ל למדדי משנה:

• מודולריות � מערכת מודולרית היא מערכת המחולקת למרכיבי תוכנה, באופ� היררכי, כ�

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

בתהלי� ה� decomposition מכריעי� כיצד לפרק את המורכבות של המערכת לכדי מודולי�,

כ� שהצימוד (להל�) ביניה� יהיה קט� ככל האפשר. כמו כ�, תכנו� מודולרי של המערכת

מאפשר שימוש חוזר (Reusability) במרכיביה ביתר קלות.

Page 6: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק 1 : מבוא 17

• צימוד Decoupling / (Coupling) � אלו ה� שני הפכי�: בתכנו� מערכת אנו מנסי� להשיג

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

מינימלי. כמעט כל ה� patterns מקטיני� את הצימוד שבי� מרכיבי� שוני� ה� ע"י שמוש

.(Forwarding) בפולימורפיז� וה� ע"י שימוש בהפנייה

לדוגמא, ה� Command (עמוד 185) מקטי� את הצימוד שבי� יוז� הפקודה לבי� העצ�

המקבל ומבצע אותה. יתר על כ�, היוז� עצמו אינו מכיר ולכ� ג� לא תלוי בסוגי ה�

Commands הקיימי� במערכת, בזכות המבנה הפולימורפי שלה�. מה שאומר ששינוי כלשהו במבצעי הפקודות, או הוספת Commands חדשי� למערכת, אינ� מצריכי� הידור מחודש

שלו.

ה� Proxy (עמוד 105) מקטי� את הצימוד שבי� קוד הלקוח לבי� עצ� נתו� ע"י חציצה בי�

השניי� וביצוע הפנייה (Forwarding) של קריאות הלקוח לעצ� המטרה.

• ניצול מקו טוב יותר � בתכנו� נכו� יותר של המערכת נית� לצרו� פחות מקו� בזכרו�

התכנית, ה� זה שבשימוש ע"י הקוד וה� זה שבשימוש ע"י הנתוני�. ה� Proxy (עמוד 105) וה�

Flyweight (עמוד 162) מספקי� ניצול טוב יותר של זכרו� התכנית ע"י שימוש בשיתו�.

• ניצול זמ� טוב יותר � הדר� שבה מבוצעות פעולות במערכת יכולה להשפיע בסדרי גודל על

ביצועי הזמ� שלה. לדוגמא, שימוש בפולימורפיז� בתכנו� OO הוא יעיל יותר משימוש

במשפטי תנאי כגו�: switch-case � קריאה לפונקציה וירטואלית מתבצעת ב� O(1), בעוד ש�

switch-case בוחר את הכניסה המתאימה ב� O(n), כאשר n הוא מספר ה� �caseי� שבמשפט.

מגוו� של patterns התנהגותיי� מייעלי� את זמ� הביצוע של משימות באופ� הנ"ל:

Command (עמוד 185), State (עמוד 199), Visitor (עמוד 232), Prototype (עמוד 60), Prototype-based Factory (עמוד 64)

פרמטר זמ� נוס� הוא מש� הפיתוח של המערכת: ג� כא�, נית� בבירור לומר שתוכנה

מודולרית ופשוטה יותר תהיה בעלת מש� פיתוח קצר יותר מזה של מערכת פחות מודולרית.

• תלות (Dependency) / אי�תלות � עפ"י דרישות היישו�, אנו משתדלי� להבי� אילו תלויות

עלולות להכביד על ביצוע שינויי� והרחבות במערכת כבר בשלב התכנו�. בתכנו� שלוקח

בחשבו� שינויי� עתידיי� (”Design for Change“) מקטיני� למינימו� את התלויות

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

לדוגמא, א� אלגורית� המוגדר ע"י פונקציה במחלקת תוכנה כלשהי עשוי להשתנות, וא�

מעבר לכ� האפשרות להחליפו באלגוריתמי� אחרי� באופ� דינמי עשויה לקד� את הפיתוח,

רצוי לשקול שימוש ב� Strategy (עמוד 245).

• יכולות דינמיות � פה אנו מדברי� על האפשרות לבצע שינויי� ותוספות בזמ� ריצה. לדוגמא,

תכנו� מסויי� של יישו� הכולל תפריט עשוי לטפל בכל האפשרויות הקיימות בתפריט בזמ�

קומפילציה. אול�, הא� נית� להוסי� פריטי� או להסיר פריטי� מהתפריט בזמ� ריצה?

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

Page 7: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 18

Command (עמוד 185) מתאר דר� יעילה למענה לדרישה זו.

באופ� דומה, State (עמוד 199) מספק יכולת דינמית בקביעת מצב העצ�, כמו ג� להוסי�

ולבטל מצבי� בזמ� ריצה. Strategy (עמוד 245) מספק יכולת דינמית בקביעת סוג

האלגורית� שיופעל בקריאה לפונקציה מסויימת של עצ� נתו�.

patterns מיפוי דרישות ספציפיות ל�

design patterns מיועדי� למת� מענה לדרישות מסויימות, בהקשר נתו�. בסעי� זה נראה מיפוי של דרישות ספציפיות ל� patterns המתאימי�:

• אי�תלות באופ� הייצוג והמימוש של העצ� � לפי דרישה זו קוד הלקוח לא צרי� להיות מודע

לפרטי הקוד של המחלקה.

Adapter (156), Bridge (166), Facade (133), Proxy (105), Memento (224)

• אי�תלות באופ� יצירת העצ� � קוד הלקוח לא צרי� להיות מודע לאופ� יצירת העצמי�.

במקרי� רבי�, דרישה זו היא תוצאה ישירה של הדרישה הקודמת.

Prototype-based Factory (64), Factory Method (73), Abstract Factory (72),

Builder (77), Proxy (105)

• אי�תלות באלגורית� � נדרשת יכולת הרחבה או שינוי של אלגורית� מסויי� בעצ� במהל�

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

Strategy (245), Template Method (240), Visitor (232), Iterator (209)

• אי�תלות בי� אופ� ייצוג נתוני� לבי� הצגת� � הפרדה בי� מודל הנתוני� של היישו� לבי�

ההצגה הויזואלית שלה� מפשטת את תהלי� הפיתוח.

MVC (180)

Page 8: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק 1 : מבוא 19

Reference

The Timeless Way of Building, Christopher Alexander,Oxford University Press, 1979.

[Alexander79]

Object Oriented Analysis and Design with Applications,Grady Booch ,Benjamin Cummings, 1997

הספר כולל טכניקות תיכו� מונחה עצמי� כלליות, ובכ� הוא משמש

.[Gamma 1994] כמשלי� ל�

[Booch97]

The Unified Modeling Language User Guide, Grady Booch,James Rumbaugh, Ivar Jacobson, Addison Wesley, 1999

ספר מקי� ללימוד UML, מאת האבות היוצרי� של תק� זה. החומר

מובא בצורה שוטפת וברורה, ע� תרשימי� רבי� ודוגמאות ממערכות

עדכניות.

[Booch99]

Design Patterns: Elements of Reusable Object-OrientedSoftware, Erich Gamma, Richard Helm, Ralph Johnson, andJohn Vlissides. (GOF), Addison Wesley 1995.

המקור הרשמי לנושאי Design Patterns. התוכ� ברור ומובא בצורה

נוחה לקריאה. עקב גילו של הספר, מוסכמות הסימוני� והדוגמאות

המובאות בו לא עדכניות.

[Gamma95]

Effective C++, 2nd Edition, Scott Meyers, Addison Wesley,1998

[Meyers98]

More Effective C++, Scott Meyers, Addison Wesley, 1996[Meyers96]

מדרי� מקצועי, מאיר סלע, מרכז ההדרכה עיט� (2000), שנת C++ 2002

ספר מקי� ומקצועי בנושא שפת ++C בפרט ותיכו� מונחה עצמי� בכלל.

ספר זה שבהוצאתנו כולל תיאור של כלל מרכיבי שפת ++C העדכנית.

[MH-C++02]

The design and evolution of C++, Bjarne Stroustrup , AddisonWesley, 1994

למרות גילו של הספר, הוא עדיי� משמש כאחד המקורות המרהיבי�

להבנת מבנה שפת ++C. המחבר, שהוא ג� יוצר השפה, מביא את

השיקולי� השוני� שעמדו בבחירת מנגנוני� מסוימי� לשפה ובדחיית

אחרי�, ובכ� מרחיב את הבנת הקורא ב� ++C בפרט ובתוכנה בכלל.

[Strous94]

Page 9: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 20

The C++ Programming Language, 3rd Edition, BjarneStroustrup , Addison Wesley, 1997

ספר התנ"� לשפת התכנות ++C, מאת יוצר השפה. הספר מקי� מאוד

ומעמיק מאוד באופ� בלתי מתפשר, לעיתי� א� על חשבו� הדידקטיות.

התוכ� מצטיי� בניסוח מדויק וזהיר.

[Strous97]

Pattern Hatching, Design Patterns Applied, John Vlissides,Addison Wesley 1998.

[Vlissid98]

Page 10: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 51

patterns . 3 בייצור עצמי�

ה� patterns שבפרק זה עוסקי בייצור של עצמי, עבור מקרי בה משימה זו אינה

טריוויאלית, או שצריכה להתבצע תחת מגבלות מסוימות.

• Singleton � הגבלת מספר העצמי המיוצרי ממחלקה מסוימת בתכנית ל� 1, ומת� גישה

גלובלית לעצ היחיד.

• Prototype � ייצור פולימורפי של עצ עפ"י אבטיפוס (prototype) נתו� ע"י שיבוט.

• Prototype-based Factory � ייצור פולימורפי של עצ עפ"י מפתח, תו� שימוש ב�

.Prototype

כמו כ� נסקור בקצרה מספר patterns סטנדרטיי נוספי:

• Abstract Factory � ממשק לייצור משפחות עצמי ללא ציו� הטיפוס הקונקרטי שלה.

• Factory Method � פונקציה לייצור עצ המוגדרת במחלקת הבסיס, כשהמחלקות הנגזרות

מחליטות איזה עצ בדיוק לייצר.

• Builder � הפרדת הייצור של עצ מורכב מהייצוג שלו, כ� שאותו תהלי� ייצור יאפשר לבנות

ייצוגי שוני של העצ.

כסיכו לסעי� זה נראה כיצד נית� לממש Serialization במערכת מונחית עצמי תו� שימוש ב�

patterns הנ"ל.

Page 11: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 52

Singleton

בעיה

נתונה מחלקת מערכת System המספקת שירותי מערכת שוני�: שירותי שעו, שירותי ניהול

זיכרו, טעינת ספריות דינמיות (DLL), וכ קבלת מידע על תכונות המערכת הנוכחית:

+System()+time_service()+mem_service()+load_library()+get_property()

-properties

System

קוד המחלקה:

// system.h#include <string>#include <map>using namespace std;

class System{public:

System() { properties["os"]="Windows"; properties["lang"]="Heb";}void time_service() { /*...*/ }void mem_service() { /*...*/ }void load_library (string lib) { /*...*/ }string get_property(string name) const { returnproperties[name];}

private:map<string, string> properties;

};

דרישות

אנו מעוניני� שמ� System יהיה מופע אחד לכל היותר בתכנית. כמו כ, אנחנו מעוניני� לספק

גישה גלובלית לעצ� היחיד של המחלקה. יש לשי� לב לדרישות מהפתרו:

• לכל היותר עצ� אחד מהמחלקה System יהיה בתכנית. משמעות הדבר, שייתכ מצב בו לא

יהיה ג� עצ� אחד � במידה ולא נעשה שימוש בו בריצת התכנית.

Page 12: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 53

• הפתרו� צרי� להיות כפוי על כל קוד התכנית � כלומר, יש להבטיח שלא ייווצר יותר מעצ�

יחיד בתכנית א� לא כתוצאה משגיאה של מתכנת/ת.

• יש לאפשר גישה לעצ� היחיד מכל מקו� בתכנית, כלומר, הגישה לעצ� צריכה להיות

גלובלית.

פתרו� שגוי

:.h פתרו� 1: הגדרת העצ� כגלובלי. נכריז על העצ� בקוב� ה�

system.h:#include <string>#include <map>using namespace std;

class System{...};

extern System g_system; // declaration of global system object

ונגדיר אותו בקוב� המימוש:

system.cpp:#include “system.h”

System g_system; // definition of global system object

קוד המשתמש יפעיל את השירותי� של g_system, למשל כ�:

g_system.load_library(“my_lib.dll”);

מה לא בסדר בפתרו� זה?

− אי� מניעה של אפשרות ייצור עצמי� נוספי� מהמחלקה. עמידות הפתרו� נתונה

לחסדיו של קוד המשתמש � היא אינה נכפית עליו ע"י המהדר.

− בדרישות הבעיה צויי� שיש לאפשר ייצור עצ� אחד לכל היותר, ולא לייצר אותו א�

לא נעשה בו שימוש. כא� אנו מקצי� את העצ� תמיד.

− "זיהו�" מרחב השמות הגלובלי � המשתנה g_system נוס� למרחב השמות הגלובלי.

במערכות גדולות מאוד, קיימת הסתברות להתנגשות ע� שמות זהי� במרחב הגלובלי,

ונדרשות מוסכמות במת� שמות בכדי למנוע זאת. לדוגמא, נהוג להוסי� לשמות

במרחב השמות הגלובלי 3 אותיות המציינות את ש� תת�המערכת לה משתיי� הש�.

Page 13: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 54

− בעיה חמורה במיוחד עלולה לצו� באיתחול המערכת: נניח שבמערכת מספר עצמי

Singleton כנ"ל � DB, Logger, Clock, System � ובאיתחול שלה� (ב� constructor) ה� תלויי� הדדית עפ"י הגר� הבא:

Clock

System

Logger

DB

לדוגמא, ח� מ� DB ל� Logger מציי� שב� constructor של המחלקה DB עושי� שימוש בעצ�

.DB להיווצר לפני יצירת Logger לכ� על העצ� .Logger ה�

אול�, מכיוו� שב ++C/C לא מוגדר סדר על יצירת העצמי� הגלובליי� (המוגדרי� בקבצי�

שוני�), מתעוררת פה בעיה איתחול חמורה. הדרכי� להתמודדות ע� בעיה זו ה� להגדיר את כל

העצמי� הגלובליי� בקוב� מימוש אחד (ואז סדר היצירה הוא עפ"י סדר הגדרת�), או לבצע 2

.(double phase initialization) פאזות של איתחול

פתרו� 2: הגדרת כל ה� members כסטטיי�:

system.h:#include <string>#include <map>using namespace std;

class System{public:

static void time_service() { /*...*/ }static void mem_service() { /*...*/ }static void load_library (string lib) { /*...*/ }static string get_property(string name) const

{ return properties[name];}private:

Page 14: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 55

static map<string, string> properties;};

ובקוב� המימוש יש להגדיר את המשתני� הסטטיי� של המחלקה:

system.cpp:#include “system.h”

map<string, string> System::properties;

בפתרו� זה � לעומת הקוד� � מובטח לנו שלא יהיה נית� לייצר יותר מהעתק אחד של ה�

members של המחלקה (ייתכ� ומספר מתכנתי� ייצרו מספר מופעי� ל� System, א� ה� עדיי� יחלקו את אות� members, עקב היות� סטטיי�).

כמו כ�, מרחב השמות הגלובלי לא מזוה�, מכיוו� שאי� צור� בייצור עצ� מהמחלקה � השירותי�

שבה מופעלי� בהקשר למחלקה, למשל כ�:

System::load_library(“my_lib.dll”);

מה לא תקי� בפתרו� זה?

− כמו בפתרו� הקוד�, ג� כא� ה� members מוקצי� תמיד, ג� א� לא נעשה בה� כל

שימוש בריצת היישו�.

− כמו בפתרו� הקוד�, סדר היצירה של עצמי� סטטיי�, כמו גלובליי�, לא מוגדר ולכ�

הבעיה שרירה וקיימת.

פתרו�

המחלקה System תוגדר כ� Singleton. היא תכלול:

− פונקציה סטטית בש� ()instance המספקת עצ� מהמחלקה. עצ� זה יוגדר כסטטי

בפונקציה.

− ה� constructor יוגדר כ� protected בכדי למנוע ייצור עצמי� ע"י קוד חיצוני. מאותה

סיבה ג� ה� copy constructor יוכרז כ� protected (הוא לא מוגדר כ� private בכדי

.(Singleton לאפשר ירושה מה�

Page 15: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 56

-System()+time_service()+mem_service()+load_library()+get_property()+instance()

-properties

System

:C++ קוד המחלקה ב�

// system.h#include <string>#include <map>

using namespace std;

class System{public:

void time_service() { /*...*/ }void mem_service() { /*...*/ }void load_library (string lib) { /*...*/ }string get_property(string name) const { returnproperties[name]; }

// global point of access to the sole instancestatic System& instance(){

static System object;return object;

}protected:

System() { properties["os"]="Windows"; properties["lang"]="Heb";}System(const System&);

private:map<string, string> properties;

};

יש לשי� לב שה� copy constructor כלל אינו נדרש להגדרה � אול� מכיוו� שמסופק כזה

במחדל, מכריזי� עליו כ � protected ולא ממשי� אותו (היינו יכולי� לממש אותו כפונקציה

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

שבאי מימושו הוא שכעת תתקבל שגיאת הידור ג� בנסיו� של קוד המחלקה עצמה, או מחלקות

צאצאות, לנסות לייצר העתקי� של העצ�!)

קוד משתמש לדוגמא:

#include <iostream>#include "system.h"using namespace std;

Page 16: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 57

void main(){

System::instance().time_service();System::instance().mem_service();System::instance().load_library("mylib.dll");cout << "Operating system: " <<System::instance().get_property("os") << endl;cout << "Language: " << System::instance().get_property("lang")<<endl;

System s1; // error: private constructorSystem s2(System::instance());// error: private copy constructor

}

הכללה

מגדירי� מחלקה כ� Singleton כאשר מעונייני� לספק מופע אחד שלה, לכל היותר, בתכנית.

הגישה למופע זה היא גלובלית עבור כל מרכיבי התכנית:

#Singleton()+operation1()+operation2()+operation3()+instance()

Singleton

− פונקציה סטטית מספקת reference לעצ� היחיד המוגדר בתוכה כסטטי

protected מוגדרי� כ� constructors ה� −

• יתרונות:

− ה� Singleton מונע "זיהו�" של מרחב השמות בכ� שעצ� המחלקה אינו מוגדר

במרחב השמות הגלובלי. בכ� למעשה ג� מסופקת גישה תקנית לעצמי� של

.instance() המשתמש תמיד ניגש לעצמי� ע"י הפונקציה :Singletons

− Singleton זמי� תמיד למשתמש בו: בניגוד לעצמי� גלובליי� שעבור� סדר הבנייה

אינו מוגדר בתכנית ++C � ולכ� אינ� יכולי� להתייחס אחד לשני בשלבי ה�

constructors שלה� � ה� Singletons נוצרי� עפ"י סדר השימוש בה�, ולכ� לא חלה עליה� מגבלת שימוש כלשהי.

Page 17: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 58

• חסרונות:

− קשה לעשות שימוש ב� Singleton בהיררכיות ירושה. כלומר, יש קושי עבור מחלקת

.Singleton לרשת ממחלקה אחרת, או לרשת ממחלקת ה� Singleton ה�

− ה� Singleton הוא יחיד פר יישו�, הואיל והוא מוגדר כסטטי בקטע הנתוני�

.Thread פר Singleton לא נית� להגדיר בטכניקה זו .(Data Segment)

• וריאציות:

− קיימת שיטה נוספת להגדרת Singleton: נית� להגדיר מצביע לעצ� היחיד כסטטי

במחלקה (static member), ולייצר אותו בפע� הראשונה שנקראת הפונקציה

הסטטית ()instance. שיטה זו היא מעט יותר מסורבלת ובעלת חסרו� משמעותי: ה�

[Vlissid98] אינו נקרא בסו� התכנית (ראה/י דיו� ב� Singleton של ה� destructorבסעי� ”To kill a Singleton“). בשפות כגו� #Java/C הבעיה לא קיימת בזכות ה�

.Garbage Collector

Java ב� Singleton מימוש

ב� Java לא קיי� מנגנו� של משתני� סטטיי��מקומיי�. לכ� אפשרות המימוש היחידה היא זו

.static-member של

:static member בשיטת ה� Singleton דוגמא למימוש

class Singleton{

private static Singleton m_instance; // the singleton object

public static Singleton instance() // static access method{

if (m_instance == null)m_instance = new Singleton();

return m_instance;}protected Singleton() {...} // protected constructor

… // rest of the class

}

• Thread Safety: במערכת מרובת Threads, עלול להיווצר מצב שבו שני Threads (או יותר)

Threads זה יכול לקרות כאשר מבוצעת החלפת .Singletonיבצעו את שורת היצירה של ה�

מיד לאחר שורת הבדיקה

if (m_instance == null)<<context switch>>m_instance = new Singleton();

נית� למנוע בעיה זו ע"י הוספת מנגנו� סינכרו� � נית� להגדיר את קטע יצירת העצ� כ�

:synchronized

public static Singleton instance() {

Page 18: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 59

synchronized(Singleton.class) { // protect critical codeif (m_instance == null)

m_instance = new Singleton();}return m_instance;

}

יש לשי� לב לכ� שההגנה מבוצעת בהקשר המחלקה (Singleton.class) מכיוו שהפונקציה היא

סטטית, והיא נקראת בהקשר זה.

• הערות:

− א� מחלקת ה� Singleton מממשת את java.io.Serializable הרי שנית

.deserialization לייצר יותר מעצ� אחד ממנה ע"י ביצוע חוזר של

− מכיוו שה� constructor מוגדר כ� protected, יכולות מחלקות צאצאות של

Singleton או מחלקות המשתייכות לאותו ה� package לעקו� את מגבלת הייצור שלו. א� רוצי� למנוע זאת, נית להגדיר את ה� constructor כ� private, אול�

.Singleton בכ� ג� תמנע אפשרות ירושה מה�

C# ב� Singleton מימוש

הקוד ב� #C דומה לזה של Java, ע� מעט הבדל במנגנו הסינכרו ובמודל השיקו�:

class Singleton{

protected static Singleton m_instance; // the singleton object

public static Singleton instance() // static access method{

lock(typeof(Singleton)) { // protect critical codeif (m_instance == null)

m_instance = new Singleton();}return m_instance;

}protected Singleton() {/*...*/} // protected constructor

}

ג� כא אנו מבצעי� הגנה מפני גישה של יותר מ� Thread אחד ע"י מנגנו הסינכרו lock, שמג

.typeof(Singleton) המתקבל מ� (Type מסוג) Singleton על טיפוס המחלקה של

Page 19: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 60

Prototype

בעיה

נתונה היררכית מחלקות הודעות:

+set()+print()

«interface»Message

+set()+print()

-m_number-m_image

Fax

+set()+print()

-m_address-m_text

Mail

+set()+print()

-m_text

Memo

הבעיה: כיצד לייצר עצ� כהעתק של עצ� הנתו� באופ� פולימורפי.

למשל, הפונקציה הבאה מקבלת כפרמטר מצביע פולימורפי, והיא מעונינת לייצר העתק שלו:

void f(Message *pm){

Message *new_msg = ???//...

}

מכיוו� שלא ברור מהו הטיפוס המדויק של העצ� המוצבע ע"י pm אי� דר� פשוטה לייצר עצ�

דומה לו.

Page 20: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 61

פתרו�

נוסי� פונקציה וירטואלית בש� ()clone להיררכיה של ההודעות שמחזירה העתק של העצ�:

+set()+print()+clone()

«interface»Message

+set()+print()+clone()

-m_number-m_image

Fax

+set()+print()+clone()

-m_address-m_text

Mail

+set()+print()+clone()

-m_text

Memo

הפונקציה ()clone היא למעשה מעי� copy constructor וירטואלי. היא תוגדר כוירטואלית

טהורה במחלקת הבסיס כ�:

class Message{public:

virtual ~Message() {}virtual Message * clone() const = 0;virtual void set(const string s1, const string s2) = 0;virtual void print() const = 0;

};

יש לשי� לב שהפונקציה מחזירה מצביע פולימורפי ל� Message. כ�, למשל, תדרוס המחלקה

Fax את הפונקציה:

class Fax : public Message{public:

Fax() : m_number(0) {}Fax(const string num, const string image) :m_number(atol(num.c_str())), m_image(image){}virtual Message* clone() const { return new Fax(*this); }virtual void set(const string num, const string image){m_number=atol(num.c_str()); m_image=image;}virtual void print() const { cout << " * Fax: num=" << m_number<< " Image=" << m_image << "\n";}

private:long m_number;string m_image;

};

וכ� תמומש הפונקציה ()f שלעיל:

Page 21: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 62

void f(Message *pm){

Message *new_msg = pm->clone();// ...

}

הכללה

Prototype (הנקרא ג� ”Virtual Constructor“) הוא פתרו� למצב בו צרי� לייצר עצ� בזמ� ריצה, שרק טיפוסו הפולימורפי ידוע בזמ� הידור.

תרשי� כללי:

+clone()

Prototype

+clone()

ConcretePrototype1

+operation()

Client

+clone()

ConcretePrototype2p = prototype->clone()

prototype

return copy of self return copy of self

• יתרונות:

− מודולריות: קוד הלקוח אינו תלוי בטיפוסי� המסוימי� הנגזרי� ממחלקת הבסיס �

הפונקציה ()clone תחזיר תמיד העתק של העצ� הנתו�.

− יעילות: העתקת העצ� מבוצעת באופ� מיידי, בניגוד לשאילתת טיפוס הצורכת זמ�

ומקו�.

• חסרונות:

,clone() לא נית� להעביר פרמטרי� מטיפוסי� שוני� עפ"י העצ� המיוצר לפונקציה −

הואיל והממשק שלה חייב להיות אחיד (פולימורפי). כתחלי�, יש לספק פונקציה

לקביעת מצב העצ� (()set) שתיקרא מייד לאחר העתקת העצ�.

− יש קושי בהחלטה כיצד להעתיק את העצ�: העתקה רדודה (Shallow Copy) או

העתקה עמוקה (Deep Copy). א� העצ� כולל מצביעי�, קיי� קושי בהחלטה הא�

לספק עצ� החולק את המצביעי�, או לספק עצ� ע� מידע כולל חדש.

Page 22: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 63

בדר� כלל מופעל ה� copy constructor בפונקציה ()clone, והוא זה ש"מחליט" כיצד

להעתיק את העצ�, אול� נית� להפעיל ג� constructor מחדל, למשל.

• וריאציות : Stroustrap מציי� בספרו [Strous97] במסגרת ה� Relaxation Rules את

האפשרות (בהתא� למימוש הקומפיילר) להחזיר במחלקה הנגזרת מצביע לטיפוס שלה,

כלומר:

class Base{

...virtual Base * clone() const = 0;

};

class Derived : public Base{

...virtual Derived * clone() const { return new Derived(...); }

};

זה יאפשר שימוש לא פולימורפי בפונקציה ()Derived::clone ג� ללא צור� ב� casting. לא

הרבה קומפיילרי� תומכי� באפשרות זו כיו�.

• שימושי� ידועי�:

− Java כוללת במחלקת הבסיס שלה, Object, את השירות ()clone המחזיר מצביע

מסוג Object לעצ� הנוכחי, תו� שימוש במנגנו� השיקו�. בהיות Object בסיס לכל

.Java לכל עצמי Prototype המחלקות, בכ� מסופק ממשק

יש לשי� לב שהמחלקות הנגזרות אינ� צריכות לדרוס את הפונקציה ()clone � גירסת

(Reflection מבצעת את כל העבודה תו� שימוש במודל השיקו� Object הבסיס

(Model. מחלקת Java צריכה לממש את הממשק Cloneable בכדי לציי� שהיא מעוניינת לספק שירות cloning (הממשק אינו כולל פונקציה כלשהי).

− באופ� דומה ל� Java, ג� ב� #C קיימת תמיכה ב� cloning כבר במחלקת הבסיס,

System.Object. אול� כא� יש הבחנה בי� העתקה רדודה (Shalow Copy) לבי� :(Deep Copy) העתקה עמוקה

MemberwiseClone() .1 מבצעת העתקה רדודה, כאשר המצביעי� בעצ�

החדש בעלי ער� זהה לאלו שבעצ� המקור.

Clone() .2 : א� עצ� מסויי� מעוניי� לאפשר העתקה עמוקה שלו, עליו לממש את הממשק IClonable תו� מימוש הפונקציה ()Clone שלו.

Page 23: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 64

Prototype-based Factory

בעיה

בהמש� ליישו� ההודעות מהסעי� הקוד�, נדרש להוסי� לתכנית מחלקת dialog לבחירת הודעה

חדשה:

+set()+print()+clone()

«interface»Message

+set()+print()+clone()

-m_number-m_image

Fax

+set()+print()+clone()

-m_address-m_text

Mail

+set()+print()+clone()

-m_text

Memo

+add_button()+get_selected()+show()+run()

NewMessageDialog

המחלקה NewMessageDialog מייצגת תיבת dialog לבחירת סוג הודעה חדשה. המחלקה

כוללת פונקציה בש� ()show לקבלת הבחירה של המשתמש � זה יכול להיות אינדקס או מחרוזת

המתארת את טיפוס ההודעה.

Page 24: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 65

תיבת ה� dialog מציגה למשתמש שלושה כפתורי� לבחירת סוג הודעה חדשה שברצונו לשלוח:

New Message

Fax

Mail

Memo

Choose type ofmessage

שאלה: כיצד לטפל בבחירת המשתמש ובייצור ההודעה החדשה?

פתרו� שגוי

נבצע ()switch על אינדקס ההודעה המוחזר מהפונקציה ()show, ועל פי התוצאה נבצע את הקוד

המתאי�:

#include "message.h"

class NewMessageDialog{

...int show(); // display dialog and return selected indexMessage * run(){

Message *pm;int i = show(); // get message type indexswitch(i){

case 0: // Faxpm = new Fax;break;

case 1: // Mailpm = new Mail;break;

case 2: // Memopm = new Memo;break;

}return pm;

}};

Page 25: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 66

קוד משתמש לדוגמא:

int main(){

NewMessageDialog dialog;Message * p_new_msg = dialog.run();

p_new_msg->print();

// use the new message// ...

delete p_new_msg;

return 0;}

לפתרו� ע"י משפט switch שלושה חסרונות:

• הוא אינו יעיל � בכל בחירת משתמש יש לעבור על כל האפשרויות, ולבחור את הנכונה.

במקרה זה אמנ� מעט אפשרויות (3), א� במקרה הכללי, כאשר יש n אפשרויות, בממוצע

.O(n) אפשרויות, כלומר בסיבוכיות n/2 יבוצע חיפוש על

• הוא אינו מודולרי � קוד הלקוח תלוי בטיפוסי ההודעות הקיימי� במערכת וצרי� להתעדכ�

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

הנבחר לסוגי ההודעות.

• הוא אינו דינמי � לא נית� להוסי� או לבטל אפשרויות נוספות בזמ� ריצה.

Page 26: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 67

פתרו�

הפתרו� כולל שני שלבי� עקרוניי�:

1. שימוש ב� Prototype � נעשה שימוש בפונקציה הוירטואלית ()clone שמחזירה העתק של

העצ�. כמו כ�, נוסי� פונקציה וירטואלית נוספת בש� ()get_type המחזירה את ש� הטיפוס של

ההודעה:

+set()+print()+clone()+get_type()

«interface»Message

+set()+print()+clone()+get_tpe()

-m_number-m_image

Fax

+set()+print()+clone()+get_type()

-m_address-m_text

Mail

+set()+print()+clone()+get_type()

-m_text

Memo

שתי הפונקציות מוגדרות כוירטואליות טהורות במחלקת הבסיס כ�:

class Message{public:

virtual ~Message() {}virtual Message* clone() const = 0;virtual string get_type() const = 0;virtual void set(const string s1, const string s2) = 0;virtual void print() const = 0;

};

כ�, למשל, תדרוס המחלקה Mail את הפונקציות:

class Mail : public Message{public:

Mail() {}Mail(const string addr, const string text) : m_address(addr),m_text(text) {}virtual Message* clone() const { return new Mail(*this); }virtual string get_type() const { return "Mail";}virtual void set(const string addr, const string text)

Page 27: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 68

{m_address=addr; m_text=text;}virtual void print() const { cout << " * Mail: address=" <<m_address << ", text=" << m_text << "\n";}

private:string m_address;string m_text;

};

� Message מצביעי� לעצמי � Prototypes שתחזיק טבלה של Factory 2. נגדיר מחלקה בש�

עפ"י מחרוזות המתארות את סוג ההודעה. מחלקה זו תוגדר כ� Singleton, וה� dialog יפנה

אליה לייצור עצ� עפ"י מחרוזת:

+set()+print()+clone()+get_type()

Message

+set()+print()+clone()+get_tpe()

-m_number-m_image

Fax

+set()+print()+clone()+get_type()

-m_address-m_text

Mail

+set()+print()+clone()+get_type()

-m_text

Memo

+add_button()+get_selected()+show()+run()

NewMessageDialog

+create_object()+add_proto()

-map<string, Message*> m_prototypes

Factory

m_prototypes

1*

:Factory קוד המחלקה

#include <map>#include <string>using namespace std;#include "Message.h"// Factory class - Creates Message Objects by their type name.// - Singletonclass Factory{public:

void add(const Message *m) {m_prototypes[m->get_type()] = m;}Message* create_object(const string &type)

{ return m_prototypes[type]->clone(); }static Factory& instance() {// singleton access method

static Factory factory;return factory;

}protected:

Page 28: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 69

Factory() {}Factory(const Factory &);~Factory() { for(map<const string, const Message *>::iterator i=

m_prototypes.begin(); i != m_prototypes.end(); i++)delete i->second;

}private:

map<const string, const Message *> m_prototypes;};

(cloning) תציג את ההודעות ובבחירת המשתמש בכפתור מסוי�, יבוצע שיבוט dialog תיבת ה�

של העצ� המתאי� בטבלה:

class NewMessageDialog{public:

void add_button(string name) {}string show();Message * run(){

string sel = show();return Factory::instance().create_object(sel);

}};

:Factory פונקציה לרישו� טיפוסי ההודעות ב�

void register_prototypes(){

Factory::instance().add_proto("Fax", new Fax);Factory::instance().add_proto("Mail", new Mail);Factory::instance().add_proto("Memo", new Memo);

}

פונקציה זו יכולה להיות גלובלית או במסגרת ה� Facade (להל�, פרק 4), לדוגמא.

קוד תכנית הלקוח:

int main() {register_prototypes();NewMessageDialog dialog;Message * p_new_msg = dialog.run();

// use the new message...

delete p_new_msg;return 0;

}

Page 29: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

Design Patterns 70

כפי שנית� לראות, מבנה מחלקת ה� dialog הוא כעת:

O(lg הינו קצר, ויצירת עצ� ההודעה החדש מבוצעת בסיבוכיות run() יעיל � קוד הפונקציה •

.map סיבוכיות חיפוש בטבלה � n)

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

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

• דינמי � נית� לקבוע בזמ� ריצה אילו טיפוסי הודעה זמיני� ע"י ה� Factory, כלומר, אפשר

להוסי� ל� Factory עצמי הודעה מטיפוסי� חדשי� או להסיר עצמי� קיימי�.

כמו כ�, מכיוו� שהכפתורי� מאותחלי� עפ"י וקטור ה� prototypes, אי� חשש לבילבול בי�

שמות טיפוסי ההודעה לבי� עצמי ההודעה עצמ�.

הכללה

Prototype-based Factory הוא מנגנו� לייצור עצמי� פולימורפי, תו� הפרדה בי� קוד הלקוח לקוד העצ� המיוצר: הוא מאפשר לקוד לקוח לייצר עצמי� מבלי לציי� את הטיפוס המדוייק של

העצ�, אלא רק מפתח שלו.

+clone()

«Prototype»AbstractProduct

Client

+create_object()+add_prototype()

Factory

m_prototypes

1*

+clone()

ProductA

+clone()

ProductB

• יתרונות:

− יעילות: ה� Factory מייצר עצ� עפ"י מפתח בסיבוכיות של O(lg n), כאשר n הוא

מספר ה� prototypes האפשרי.

− מודולריות: ה� קוד הלקוח וה� ה� Factory עצמו מבודדי� מהטיפוסי� המדוייקי�

של העצמי� ואינ� תלויי� בה�.

− דינמיות : נית� לקבוע בזמ� ריצה אילו טיפוסי� יהיו ניתני� לייצור בהקשר הנתו�.

Page 30: Design Patterns - Home - Eytam Robotics · 2020-02-18 · Design Patterns 14 Design Patterns ימצע החנומ וכית לש תיללכה תרגסמב וחת אוה design patterns.תומדקתמ

פרק patterns : 3 בייצור עצמי� 71

יש לשי� לב לכ� שתוספת טיפוס Prototype אינה מצריכה א� לא הידור מחודש של

ה� Factory. המחלקה המשתמשת (בדוגמא הנ"ל, ה� dialog) אינה תלויה א� היא

.Prototypes בטיפוסי ה�

• וריאציות:

− מפתח ה� prototypes יכול להיות מחרוזת, מזהה מספרי או עצ� RTTI של מחלקת

.Prototype ה�

− ב� ++C נית� להגדיר template של Prototype-based Factory לשימוש כללי.

דוגמא: Prototype-based Factory כ� template ב� ++C לטיפוסי מפתח ו�

prototype כלליי�:

#ifndef FACTORY_H#define FACTORY_H#include <map>using namespace std;

// Factory class - Creates Objects by a key// - Singletontemplate <class Key, class Object>class Factory {public:

void add_proto(const Key key, const Object *proto) {m_prototypes[key] = proto;

}Object* create_object(const Key &key) {

return m_prototypes[key]->clone();}static Factory& instance() { // singleton access method

static Factory factory;return factory;

}~Factory() {

for(map<const Key, const Object *>::iterator i= m_prototypes.begin(); i != m_prototypes.end(); i++)

delete i->second;}

private:map<const Key, const Object *> m_prototypes;Factory() {}Factory(const Factory &);Factory& operator=(const Factory&);

};#endif