Professional Documents
Culture Documents
Design Patterns
מאיר סלע
אי להעתיק ,לשכפל או לצל ספר זה או קטעי ממנו ,בשו צורה ובשו אמצעי אלקטרוני,
אופטי או מכני לכל מטרה שהיא ,ללא אישור בכתב מההוצאה לאור.
13 פרק :1מבוא
.1מבוא
נושאי הפרק:
• Design Patternsהגדרה ,מאפייני
,יישו
• מדדי
בפיתוח תוכנה וכיצד Design Patternsמסייעי
בהשגת
• Referenceמקורות ספרות
Design Patterns 14
Design Patterns
עצמי מונחה design patternsהוא תחו במסגרת הכללית של תיכו
) ,(Object Oriented Designהכולל טכניקות תיכו ותכנות מתקדמות.
המקור התיעודי העיקרי ל patternsהוא הספר] .[Gamma95לספר ארבעה מחברי ,ולכ ה
מכוני לפעמי בקיצור ג .Gang Of Four GOFמחברי הספר עצמ מעידי שמקור
ההשראה העיקרי עבור היה ספרו של כריסטופר אלכסנדר ] [Alexander79שעסק בתכנו
וארכיטקטורה אורבניי.
בספר זה נסקור את ה patternsהתקניי והמוכרי בתעשיית התוכנה .לכל patternנית ש
מזהה ותיאור בשלושה חלקי:
−תיאור הקשר ) (contextהבעיה תו התבוננות בדוגמא
−תיאור הפתרו בצורת תרשי תיכו ,UMLכמו ג קוד דוגמא ב .C++/Java/C#
−הכללת הפתרו למקרה הכללי תו ציו קשרי ע patternsאחרי ,וריאציות שונות
של הפתרו ,השלכות ,ושימושי לדוגמא.
כפי שנאמר ,המקור העיקרי ל patternsהוא הספר ] .[Gamma95עקב גילו ,שפת התרשימי
שבו אינה עדכנית )לא ,(UMLמערכות העצמי ודוגמאות הקוד שבו מיושנות .ספר זה עושה
שימוש בתרשימי ,UMLכולל עדכוני רבי ,תוספות ודוגמאות ממערכות עצמי מודרניות.
תוצרי לוואי:
• לימוד ותרגול UMLכשפה לתיאור מודלי תוכנה מרבית הדיוני שבספר זה מתבצעי
ברמת התיכו ב ,UMLכאשר פה וש מובאות דוגמאות קוד .אחת התוצאות של לימוד ה
patternsהיא הכרת UMLבצורה מחודדת ומעמיקה.
• התנסות בתיכו ובמעבר מתיכו למימוש שיקולי התיכו שמלווי חלק גדול מה patterns
מספקי התנסות עשירה בבחינת השפעת במעבר למימוש.
Design Patterns 16
מדדי
בפיתוח תוכנה
המטרה המשותפת לכל ה patternsשבספר זה היא פיתוח תוכנה "טובה" יותר .השאלה
הראשונה שעולה מכא היא "מהי תוכנה טובה יותר?" לש כ קיימי מספר מדדי מקובלי
להערכת תוכנה:
• גמישות היכולת לבצע שינויי בתוכנה ללא מאמ רב.
• הרחבה היכולת להרחיב את התוכנה )בדר כלל פרוייקטי תוכנה מתרחבי ע הזמ(.
• יעילות ניצול משאבי מקו וזמ שצורכי מרכיבי המערכת.
• בהירות היכולת ללמוד את המערכת ללא מאמ רב ובזמ קצר.
• ניידות יכולת הסבה של התוכנה לספריות ,מערכות ומחשבי שוני.
במילי אחרות ,תוכנה היא טובה יותר ככל שהיא יעילה יותר ,גמישה יותר בפני ביצוע שינויי,
מאפשרת תוספות בצורה קלה ופשוטה יותר וככל שנית להסב אותה לסביבות שונות ביתר
קלות.
מדד אחר שמקובל להגדיר באופ כללי הוא פשטות ,והוא כולל בתוכו את כל המדדי האחרי:
ככל שהמערכת פשוטה וטבעית יותר ,היא מובנת יותר ,נוחה יותר להרחבה ולשינוי ולכ טובה
יותר .באנגלית קיי קיצור KISלביטוי "."Keep It Simple
• צימוד ) 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עמוד ) State ,(185עמוד ) Visitor ,(199עמוד ) Prototype ,(232עמוד ,(60
) Prototype-based Factoryעמוד (64
פרמטר זמ נוס הוא מש הפיתוח של המערכת :ג כא ,נית בבירור לומר שתוכנה
מודולרית ופשוטה יותר תהיה בעלת מש פיתוח קצר יותר מזה של מערכת פחות מודולרית.
• תלות ) / (Dependencyאיתלות עפ"י דרישות היישו ,אנו משתדלי להבי אילו תלויות
עלולות להכביד על ביצוע שינויי והרחבות במערכת כבר בשלב התכנו .בתכנו שלוקח
בחשבו שינויי עתידיי )” (“Design for Changeמקטיני למינימו את התלויות
במרכיבי העשויי להשתנות.
לדוגמא ,א אלגורית המוגדר ע"י פונקציה במחלקת תוכנה כלשהי עשוי להשתנות ,וא
מעבר לכ האפשרות להחליפו באלגוריתמי אחרי באופ דינמי עשויה לקד את הפיתוח,
רצוי לשקול שימוש ב ) Strategyעמוד .(245
• יכולות דינמיות פה אנו מדברי על האפשרות לבצע שינויי ותוספות בזמ ריצה .לדוגמא,
תכנו מסויי של יישו הכולל תפריט עשוי לטפל בכל האפשרויות הקיימות בתפריט בזמ
קומפילציה .אול ,הא נית להוסי פריטי או להסיר פריטי מהתפריט בזמ ריצה?
יכולת דינמית כזו חוסכת את הצור בקידוד ובהידור מחודש בכל שינוי בתפריט .ה
Design Patterns 18
Reference
[Alexander79] The Timeless Way of Building, Christopher Alexander,
Oxford University Press, 1979.
[Booch97] Object Oriented Analysis and Design with Applications,
Grady Booch ,Benjamin Cummings, 1997
ובכ הוא משמש,הספר כולל טכניקות תיכו מונחה עצמי כלליות
.[Gamma 1994] כמשלי ל
[Booch99] The Unified Modeling Language User Guide, Grady Booch,
James Rumbaugh, Ivar Jacobson, Addison Wesley, 1999
החומר. מאת האבות היוצרי של תק זה,UML ספר מקי ללימוד
ע תרשימי רבי ודוגמאות ממערכות,מובא בצורה שוטפת וברורה
.עדכניות
[Gamma95] Design Patterns: Elements of Reusable Object-Oriented
Software, Erich Gamma, Richard Helm, Ralph Johnson, and
John Vlissides. (GOF), Addison Wesley 1995.
התוכ ברור ומובא בצורה.Design Patterns המקור הרשמי לנושאי
מוסכמות הסימוני והדוגמאות, עקב גילו של הספר.נוחה לקריאה
.המובאות בו לא עדכניות
[Meyers98] Effective C++, 2nd Edition, Scott Meyers, Addison Wesley,
1998
[Meyers96] More Effective C++, Scott Meyers, Addison Wesley, 1996
[MH-C++02] שנת,(2000) מרכז ההדרכה עיט, מאיר סלע,
מדרי מקצועיC++
2002
. בפרט ותיכו מונחה עצמי בכללC++ ספר מקי ומקצועי בנושא שפת
. העדכניתC++ ספר זה שבהוצאתנו כולל תיאור של כלל מרכיבי שפת
[Strous94] The design and evolution of C++, Bjarne Stroustrup , Addison
Wesley, 1994
הוא עדיי משמש כאחד המקורות המרהיבי,למרות גילו של הספר
מביא את, שהוא ג יוצר השפה, המחבר.C++ להבנת מבנה שפת
השיקולי השוני שעמדו בבחירת מנגנוני מסוימי לשפה ובדחיית
. בפרט ובתוכנה בכללC++ ובכ מרחיב את הבנת הקורא ב,אחרי
Design Patterns 20
patterns .3בייצור
עצמי
ה patternsשבפרק זה עוסקי בייצור של עצמי ,עבור מקרי בה משימה זו אינה
טריוויאלית ,או שצריכה להתבצע תחת מגבלות מסוימות.
• Singletonהגבלת מספר העצמי המיוצרי ממחלקה מסוימת בתכנית ל ,1ומת גישה
גלובלית לעצ היחיד.
• Prototypeייצור פולימורפי של עצ עפ"י אבטיפוס ) (prototypeנתו ע"י שיבוט.
• Prototype-based Factoryייצור פולימורפי של עצ עפ"י מפתח ,תו שימוש ב
.Prototype
כסיכו לסעי זה נראה כיצד נית לממש Serializationבמערכת מונחית עצמי תו שימוש ב
patternsהנ"ל.
Design Patterns 52
Singleton
בעיה
שירותי ניהול, שירותי שעו: המספקת שירותי מערכת שוניSystem נתונה מחלקת מערכת
: וכ קבלת מידע על תכונות המערכת הנוכחית,(DLL) טעינת ספריות דינמיות, זיכרו
System
-properties
+System()
+time_service()
+mem_service()
+load_library()
+get_property()
:קוד המחלקה
// 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 { return
properties[name];}
private:
map<string, string> properties;
};
דרישות
אנחנו מעוניני לספק, כמו כ. יהיה מופע אחד לכל היותר בתכניתSystem אנו מעוניני שמ
: יש לשי לב לדרישות מהפתרו.גישה גלובלית לעצ היחיד של המחלקה
שייתכ מצב בו לא, משמעות הדבר. יהיה בתכניתSystem • לכל היותר עצ אחד מהמחלקה
.יהיה ג עצ אחד במידה ולא נעשה שימוש בו בריצת התכנית
53 פרק patterns :3בייצור עצמי
• הפתרו צרי להיות כפוי על כל קוד התכנית כלומר ,יש להבטיח שלא ייווצר יותר מעצ
יחיד בתכנית א לא כתוצאה משגיאה של מתכנת/ת.
• יש לאפשר גישה לעצ היחיד מכל מקו בתכנית ,כלומר ,הגישה לעצ צריכה להיות
גלובלית.
פתרו שגוי
פתרו :1הגדרת העצ כגלובלי .נכריז על העצ בקוב ה :.h
system.h:
>#include <string
>#include <map
;using namespace std
class System
{
...
;}
−בעיה חמורה במיוחד עלולה לצו באיתחול המערכת :נניח שבמערכת מספר עצמי
Singletonכנ"ל DB, Logger, Clock, Systemובאיתחול שלה )ב
(constructorה תלויי הדדית עפ"י הגר הבא:
Clock
System
Logger
DB
לדוגמא ,ח מ DBל Loggerמציי שב constructorשל המחלקה DBעושי שימוש בעצ
ה .Loggerלכ על העצ Loggerלהיווצר לפני יצירת .DB
אול ,מכיוו שב C/C++לא מוגדר סדר על יצירת העצמי הגלובליי )המוגדרי בקבצי
שוני( ,מתעוררת פה בעיה איתחול חמורה .הדרכי להתמודדות ע בעיה זו ה להגדיר את כל
העצמי הגלובליי בקוב מימוש אחד )ואז סדר היצירה הוא עפ"י סדר הגדרת( ,או לבצע 2
פאזות של איתחול ).(double phase initialization
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:
55 פרק patterns :3בייצור עצמי
בפתרו זה לעומת הקוד מובטח לנו שלא יהיה נית לייצר יותר מהעתק אחד של ה
membersשל המחלקה )ייתכ ומספר מתכנתי ייצרו מספר מופעי ל ,Systemא ה עדיי
יחלקו את אות ,membersעקב היות סטטיי(.
כמו כ ,מרחב השמות הגלובלי לא מזוה ,מכיוו שאי צור בייצור עצ מהמחלקה השירותי
שבה מופעלי בהקשר למחלקה ,למשל כ:
;)”System::load_library(“my_lib.dll
מה לא תקי בפתרו זה?
−כמו בפתרו הקוד ,ג כא ה membersמוקצי תמיד ,ג א לא נעשה בה כל
שימוש בריצת היישו.
−כמו בפתרו הקוד ,סדר היצירה של עצמי סטטיי ,כמו גלובליי ,לא מוגדר ולכ
הבעיה שרירה וקיימת.
פתרו
המחלקה Systemתוגדר כ .Singletonהיא תכלול:
−פונקציה סטטית בש )( instanceהמספקת עצ מהמחלקה .עצ זה יוגדר כסטטי
בפונקציה.
−ה constructorיוגדר כ protectedבכדי למנוע ייצור עצמי ע"י קוד חיצוני .מאותה
סיבה ג ה copy constructorיוכרז כ ) protectedהוא לא מוגדר כ privateבכדי
לאפשר ירושה מה .(Singleton
Design Patterns 56
System
-properties
-System()
+time_service()
+mem_service()
+load_library()
+get_property()
+instance()
class System
{
public:
void time_service() { /*...*/ }
void mem_service() { /*...*/ }
void load_library (string lib) { /*...*/ }
string get_property(string name) const { return
properties[name]; }
כלל אינו נדרש להגדרה אול מכיוו שמסופק כזהcopy constructor יש לשי לב שה
ולא ממשי אותו )היינו יכולי לממש אותו כפונקציהprotected מכריזי עליו כ,במחדל
היתרו. וג אז הוא גור לשגיאת הידור בנסיו של קוד חיצוני למחלקה לעשות בו שימוש,ריקה
או מחלקות,שבאי מימושו הוא שכעת תתקבל שגיאת הידור ג בנסיו של קוד המחלקה עצמה
(! לנסות לייצר העתקי של העצ,צאצאות
:קוד משתמש לדוגמא
#include <iostream>
#include "system.h"
using namespace std;
57 פרק patterns :3בייצור עצמי
)(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
הכללה
מגדירי מחלקה כ Singletonכאשר מעונייני לספק מופע אחד שלה ,לכל היותר ,בתכנית.
הגישה למופע זה היא גלובלית עבור כל מרכיבי התכנית:
Singleton
)(#Singleton
)(+operation1
)(+operation2
)(+operation3
)(+instance
• חסרונות:
−קשה לעשות שימוש ב Singletonבהיררכיות ירושה .כלומר ,יש קושי עבור מחלקת
ה Singletonלרשת ממחלקה אחרת ,או לרשת ממחלקת ה .Singleton
−ה Singletonהוא יחיד פר יישו ,הואיל והוא מוגדר כסטטי בקטע הנתוני
) .(Data Segmentלא נית להגדיר בטכניקה זו Singletonפר .Thread
• וריאציות:
−קיימת שיטה נוספת להגדרת :Singletonנית להגדיר מצביע לעצ היחיד כסטטי
במחלקה ) ,(static memberולייצר אותו בפע הראשונה שנקראת הפונקציה
הסטטית )( .instanceשיטה זו היא מעט יותר מסורבלת ובעלת חסרו משמעותי :ה
destructorשל ה Singletonאינו נקרא בסו התכנית )ראה/י דיו ב ][Vlissid98
בסעי ” .(“To kill a Singletonבשפות כגו Java/C#הבעיה לא קיימת בזכות ה
.Garbage Collector
}
• :Thread Safetyבמערכת מרובת ,Threadsעלול להיווצר מצב שבו שני ) Threadsאו יותר(
יבצעו את שורת היצירה של ה .Singletonזה יכול לקרות כאשר מבוצעת החלפת Threads
מיד לאחר שורת הבדיקה
)if (m_instance == null
>><<context switch
;)(m_instance = new Singleton
נית למנוע בעיה זו ע"י הוספת מנגנו סינכרו נית להגדיר את קטע יצירת העצ כ
:synchronized
)(public static Singleton instance {
59 בייצור עצמיpatterns :3 פרק
C# בSingleton מימוש
: ע מעט הבדל במנגנו
הסינכרו
ובמודל השיקו,Java דומה לזה שלC# הקוד ב
class Singleton
{
protected static Singleton m_instance; // the singleton object
שמג,lock
אחד ע"י מנגנו
הסינכרוThread ג כא
אנו מבצעי הגנה מפני גישה של יותר מ
.typeof(Singleton) ( המתקבל מType )מסוגSingleton על טיפוס המחלקה של
Design Patterns 60
Prototype
בעיה
נתונה היררכית מחלקות הודעות:
»«interface
Message
)(+set
)(+print
פתרו
: להיררכיה של ההודעות שמחזירה העתק של העצclone() נוסי פונקציה וירטואלית בש
«interface»
Message
+set()
+print()
+clone()
תדרוס המחלקה, למשל, כ.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() וכ תמומש הפונקציה
Design Patterns 62
הכללה
) Prototypeהנקרא ג ” (“Virtual Constructorהוא פתרו למצב בו צרי לייצר עצ בזמ
ריצה ,שרק טיפוסו הפולימורפי ידוע בזמ הידור.
תרשי כללי:
Client Prototype
prototype
)(+operation )(+clone
)(+clone )(+clone
• יתרונות:
−מודולריות :קוד הלקוח אינו תלוי בטיפוסי המסוימי הנגזרי ממחלקת הבסיס
הפונקציה )( cloneתחזיר תמיד העתק של העצ הנתו.
−יעילות :העתקת העצ מבוצעת באופ מיידי ,בניגוד לשאילתת טיפוס הצורכת זמ
ומקו.
• חסרונות:
−לא נית להעביר פרמטרי מטיפוסי שוני עפ"י העצ המיוצר לפונקציה )(,clone
הואיל והממשק שלה חייב להיות אחיד )פולימורפי( .כתחלי ,יש לספק פונקציה
לקביעת מצב העצ ))( (setשתיקרא מייד לאחר העתקת העצ.
−יש קושי בהחלטה כיצד להעתיק את העצ :העתקה רדודה ) (Shallow Copyאו
העתקה עמוקה ) .(Deep Copyא העצ כולל מצביעי ,קיי קושי בהחלטה הא
לספק עצ החולק את המצביעי ,או לספק עצ ע מידע כולל חדש.
63 פרק patterns :3בייצור עצמי
זה יאפשר שימוש לא פולימורפי בפונקציה )( Derived::cloneג ללא צור ב .castingלא
הרבה קומפיילרי תומכי באפשרות זו כיו.
• שימושי ידועי:
Java −כוללת במחלקת הבסיס שלה ,Object ,את השירות )( cloneהמחזיר מצביע
מסוג Objectלעצ הנוכחי ,תו שימוש במנגנו השיקו .בהיות Objectבסיס לכל
המחלקות ,בכ מסופק ממשק Prototypeלכל עצמי .Java
יש לשי לב שהמחלקות הנגזרות אינ צריכות לדרוס את הפונקציה )( cloneגירסת
הבסיס Objectמבצעת את כל העבודה תו שימוש במודל השיקו (Reflection
) .Modelמחלקת Javaצריכה לממש את הממשק Cloneableבכדי לציי שהיא
מעוניינת לספק שירות ) cloningהממשק אינו כולל פונקציה כלשהי(.
−באופ דומה ל ,Javaג ב C#קיימת תמיכה ב cloningכבר במחלקת הבסיס,
.System.Objectאול כא יש הבחנה בי העתקה רדודה ) (Shalow Copyלבי
העתקה עמוקה ):(Deep Copy
MemberwiseClone() .1מבצעת העתקה רדודה ,כאשר המצביעי בעצ
החדש בעלי ער זהה לאלו שבעצ המקור.
: Clone() .2א עצ מסויי מעוניי לאפשר העתקה עמוקה שלו ,עליו לממש
את הממשק IClonableתו מימוש הפונקציה )( Cloneשלו.
Design Patterns 64
Prototype-based Factory
בעיה
לבחירת הודעהdialog נדרש להוסי לתכנית מחלקת,בהמש ליישו ההודעות מהסעי הקוד
:חדשה
NewMessageDialog «interface»
Message
+add_button()
+get_selected() +set()
+show() +print()
+run() +clone()
: מציגה למשתמש שלושה כפתורי לבחירת סוג הודעה חדשה שברצונו לשלוחdialog תיבת ה
New Message
Fax
Choose type of
Mail message
Memo
פתרו שגוי
ועל פי התוצאה נבצע את הקוד,show() על אינדקס ההודעה המוחזר מהפונקציהswitch() נבצע
:המתאי
#include "message.h"
class NewMessageDialog
{
...
int show(); // display dialog and return selected index
Message * run()
{
Message *pm;
int i = show(); // get message type index
switch(i)
{
case 0: // Fax
pm = new Fax;
break;
case 1: // Mail
pm = new Mail;
break;
case 2: // Memo
pm = new Memo;
break;
}
return pm;
}
};
Design Patterns 66
;)(p_new_msg->print
;delete p_new_msg
;return 0
}
לפתרו ע"י משפט switchשלושה חסרונות:
• הוא אינו יעיל בכל בחירת משתמש יש לעבור על כל האפשרויות ,ולבחור את הנכונה.
במקרה זה אמנ מעט אפשרויות ) ,(3א במקרה הכללי ,כאשר יש nאפשרויות ,בממוצע
יבוצע חיפוש על n/2אפשרויות ,כלומר בסיבוכיות ).O(n
• הוא אינו מודולרי קוד הלקוח תלוי בטיפוסי ההודעות הקיימי במערכת וצרי להתעדכ
בכל שינוי או תוספת של הודעה חדשה .בנוס ,עלולה להיווצר שגיאה בהתאמת האינדקס
הנבחר לסוגי ההודעות.
• הוא אינו דינמי לא נית להוסי או לבטל אפשרויות נוספות בזמ ריצה.
67 בייצור עצמיpatterns :3 פרק
פתרו
:הפתרו כולל שני שלבי עקרוניי
שמחזירה העתק שלclone() נעשה שימוש בפונקציה הוירטואליתPrototype שימוש ב.1
המחזירה את ש הטיפוס שלget_type() נוסי פונקציה וירטואלית נוספת בש, כמו כ.העצ
:ההודעה
«interface»
Message
+set()
+print()
+clone()
+get_type()
{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;
};
NewMessageDialog
+add_button()
+get_selected()
+show()
+run() Message Factory
* 1 -map<string, Message*> m_prototypes
+set() +create_object()
+print() +add_proto()
m_prototypes
+clone()
+get_type()
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);
}
. לדוגמא,(4 פרק, )להלFacade פונקציה זו יכולה להיות גלובלית או במסגרת ה
:קוד תכנית הלקוח
int main() {
register_prototypes();
NewMessageDialog dialog;
Message * p_new_msg = dialog.run();
delete p_new_msg;
return 0;
}
Design Patterns 70
הכללה
Prototype-based Factoryהוא מנגנו לייצור עצמי פולימורפי ,תו הפרדה בי קוד הלקוח
לקוד העצ המיוצר :הוא מאפשר לקוד לקוח לייצר עצמי מבלי לציי את הטיפוס המדוייק של
העצ ,אלא רק מפתח שלו.
Client
Factory
»«Prototype * 1
AbstractProduct
)(+create_object
)(+add_prototype
)(+clone m_prototypes
ProductA ProductB
)(+clone )(+clone
• יתרונות:
−יעילות :ה Factoryמייצר עצ עפ"י מפתח בסיבוכיות של ) ,O(lg nכאשר nהוא
מספר ה prototypesהאפשרי.
−מודולריות :ה קוד הלקוח וה ה Factoryעצמו מבודדי מהטיפוסי המדוייקי
של העצמי ואינ תלויי בה.
−דינמיות :נית לקבוע בזמ ריצה אילו טיפוסי יהיו ניתני לייצור בהקשר הנתו.
71 בייצור עצמיpatterns :3 פרק
אינה מצריכה א לא הידור מחודש שלPrototype יש לשי לב לכ שתוספת טיפוס
( אינה תלויה א היאdialog ה, המחלקה המשתמשת )בדוגמא הנ"ל.Factory ה
.Prototypes בטיפוסי ה
:• וריאציות
של מחלקתRTTI מזהה מספרי או עצ, יכול להיות מחרוזתprototypes מפתח ה−
.Prototype ה
. לשימוש כלליPrototype-based Factory שלtemplate נית להגדירC++ ב−
לטיפוסי מפתח וC++ בtemplate כPrototype-based Factory :דוגמא
: כללייprototype
#ifndef FACTORY_H
#define FACTORY_H
#include <map>
using namespace std;