תבנית עיצוב
יש לערוך ערך זה. ייתכן שהערך סובל מבעיות ניסוח, סגנון טעון שיפור או צורך בהגהה, או שיש לעצב אותו, או מפגמים טכניים כגון מיעוט קישורים פנימיים.
| ||
יש לערוך ערך זה. ייתכן שהערך סובל מבעיות ניסוח, סגנון טעון שיפור או צורך בהגהה, או שיש לעצב אותו, או מפגמים טכניים כגון מיעוט קישורים פנימיים. |
בהנדסת תוכנה, תבנית עיצוב (באנגלית: Design pattern) היא פתרון כללי לבעיה שכיחה בעיצוב תוכנה. תבנית עיצוב אינה עיצוב סופי שניתן להעבירו הישר לקוד, אלא תיאור או תבנית לדרך לפתרון בעיה, שעשויה להיות שימושית במצבים רבים. תבניות עיצוב מונחות עצמים מציגות לרוב יחסים וקשרי גומלין בין מחלקות או אובייקטים, בלי לפרט את המחלקות או אובייקטי היישום הסופיים המעורבים. אלגוריתמים אינם נחשבים כתבנית עיצוב, כיוון שהם פותרים בעיות חישוביות ולא בעיות עיצוב.[1]
עקרונות מאחורי תבניות עיצוב
ברוב תבניות העיצוב נעשה שימוש במספר רעיונות: OCP - Open Closed Principle (עיקרון הפתיחות להרחבה והסגירות לשינויים), ו-ISP - Interface Segregation Principle (עיקרון הפרדת הממשקים).
תבניות עיצוב עשויות להתפתח באופן נקודתי עבור תחום עסקי מסוים שתוכנה נכתבת עבורו. לדוגמה, מערכות מידע, מערכות טלפוניה, יישומים רפואיים וכיוצא בזה יכילו בדרך כלל פתרונות לבעיות חוזרות ונשנות האופייניות לתחום המסוים. היכולת למצות תבנית עיצוב מתוך פתרון שיושם במערכת מסוימת עוזרת לפתח מערכות דומות בעתיד באיכות גבוהה יותר.
בהיבט רחב יותר ניתן למצוא שילובים של תבניות עיצוב היכולים להיחשב כתבניות ארכיטקטורה משום שהם משפיעים על ההיבט הארכיטקטוני של התוכנה הנכתבת מעבר לסוגיית עיצוב תוכנה מקומית.[2] דוגמה לשילוב נודע מסוג זה היא תבנית Model View Controller.
היסטוריה
מקורם של תבניות העיצוב הוא מתחום הארכיטקטורה, בשנת 1977, כריסטופר אלכסנדר, ארכיטקט במקצועו, הוציא ספר[3] ובו הגדיר באופן פורמלי 253 בעיות מוכרות מעולם הארכיטקטורה ולהן פתרונות מופשטים. עשר שנים מאוחר יותר ב-1987 קנט בק ווורד קנינגהם השתעשעו ברעיון של השמה של תבניות עיצוב לעולם התכנות, הם הציגו את תוצאותיהם בוועידת OOPSLA. בנוסף הם עיצבו יחד תבנית עיצוב לעיבוד קרניים גרפיות בשפת Smalltalk.
- בשנת 1988 אריך גמא התחיל לכתוב עבודת מחקר לדוקטורט באוניברסיטת ציריך בנושא "קווים כלליים לעיבוד תוכנה".
- בשנת 1991 לאחר עבודת מחקר שארכה כשנתיים הוציא ג'יימס קופלין ספר בשם "Advanced C++ Idioms" - המכיל מגוון דוגמאות לפתרון בעיות שונות בתכנות ב-C++.
כנופיית הארבעה או Gang of Four
כינוי שניתן לאריך גמא, ריצ'רד הלם, רלף ג'ונסון וג'ון ויליסידס, מחברי הספר: Design Patterns - Elements of Reusable Object-Oriented Software. (שמם שאול מכנופיית הארבעה הסינית). ספרם שיצא ב-1994 היה הראשון שאסף ותיעד באופן מעמיק תבניות עיצוב. עשרים ושתיים תבניות העיצוב שהופיעו בספר הפכו עם השנים לתבניות העיצוב המוכרות ביותר והיוו בסיס לכל ידע נוסף שנצבר בתחום תבניות העיצוב.
בין התבניות העיקריות שתועדו:
תיעוד
הגדרת תבנית עיצוב תכיל את הפרמטרים הבאים:
- שם תבנית העיצוב וסיווגה
- תיאור מופשט של הבעיה אותה תבנית העיצוב נועדה לפתור
- הצגת הפתרון בצורה מורחבת הכוללת תרשים OMT (Object Modeling Technique) או UML (Unified Modeling Language).
- תוצאות והשלכות של יישום הפתרון המוצע
דוגמה
- שם - תבנית Singleton, תבנית יצירה
- בעיה - יש צורך במופע יחיד של מחלקה.
- פתרון - הגדרת בנית המחלקה רק בתוכה והחצנת פונקציה שרק בקריאה הראשונה אליה תיצור מופע של המחלקה (ראו פרוט בערך עצמו).
- השלכות - שימוש לא נכון בתבנית העיצוב עלול להוביל לקוד בו המחלקות בצמידות או תלות (Coupling) גבוהה.
יתרונות
הגדרת התבניות תחת רעיון אחד, ובעיקר הגדרת שם התבנית מקלות על ההבנה בין מפתחים ממקומות שונים בהתייחסות לבעיה ולדרך פתרונה, כיוון שישנה שפה משותפת.
בנוסף כיוון שהתבניות עצמן מוגדרות באופן מופשט אך בצורה פורמלית, הן אינן תלויות בשפה או בסביבת פיתוח יחידה, דבר המאפשר צבירה והמשכיות של הידע הנלמד.
כמו כן, ההתמקדות ביצירת תבניות עיצוב היא לא על הטכנולוגיה אלא על תיעוד הבעיה ופתרונה דבר שמעשיר את הספרות המקצועית בידע רב וחושף מתכנתים מתחילים לידע ברמה גבוהה.
התנגדות
לעיתים תבנית שעוצבה על ידי קבוצה מצומצמת אינה מקיפה את הבעיה מכל כיווניה, וכאשר מנסים להחיל את הפתרון על מערכת מסורבלת הדבר עולה בטעויות קריטיות או שפשוט מתעלמים מהמוסכמות של התבנית.
יש הטוענים שתבניות מאטות את ההתקדמות של מתכנתים מתחילים כיוון שהם אינם צריכים להשקיע מאמץ בפתרון בעיות סבוכות, הבעיה נוצרת במיוחד במקרים בהם מעתיקים יישום של תבנית ללא לימוד והבנה מעמיקה של הבעיה והפתרון המוצע. מתכנת מקצועי ילמד קודם את התאוריה שמאחורי התבניות ובאופן מושכל יחליט באיזו תבנית להשתמש לפתרון בעיה שצצה. כך ימנע פיתוח של תוכניות גרועות הכתובות ב"עיוורון" מוחלט.
במהלך ההתפתחות של תבניות העיצוב הוגדרו גם תבניות אשר מציעות כביכול פתרון לבעיה מסוימת, אך הפתרון המוצע הוא רע, ואינו מציג דרך נכונה להתמודדות עם הבעיה. תבניות אלו נקראות Anti Pattern. יש הטוענים שגם בין תבניות העיצוב המקובלות כמומלצות קיימות תבניות שאינן מספקות פתרון טוב לבעיה ומהוות Anti Pattern. דוגמה לתבנית כזאת היא התבנית Singleton אשר מצד אחד מקובלת על מתכנתים רבים כאחת התבניות הטובות ביותר ולדעת אחרים היא Anti Pattern. דעות סותרות אלו מראות שהסתמכות בעיניים עצומות על תבניות מוגדרות מוטעית מיסודה ויכולה לגרום לטעויות שתעלנה ביוקר הן מבחינת זמן והן מבחינת משאבים ותקציב.[4]
תבניות עיצוב נפוצות
באופן כללי, ניתן לחלק את התבניות לשלושה סוגים:[5]
תבניות יצירה
מטרת תבניות אילו היא ליצור הפשטה (Abstraction) לתהליך היצירה של אובייקטים, על ידי ביצוע הפרדה בין המערכת לבין יצירה או תצוגה של האובייקטים הנוצרים. כלומר, הידע הקונקרטי על סוג המחלקה ממנה ניצור אובייקט ותהליך היצירה עצמו יוכמסו ובנוסף, לאחר היצירה הגישה לאובייקט הנוצר תעשה באמצעות ממשק.
שם התבנית | תיאור | UML |
---|---|---|
Abstract Factory | "בית חרושת ליצירת אובייקטים" - ממשק המשמש ליצירת אובייקטים תלויים, ללא ציון המחלקות הנוצרות.
נשתמש כאשר:
|
|
Factory Method | יצירת עצמים ללא הכרה של המחלקות שלהם, ניתן יכולות למחלקות יורשות לדרוס את השיטה שהממשק חושף עם שיטה משלהם, וכך ליצור את הטיפוס שנדרש.
נשתמש כאשר:
|
|
Builder | הפרדת יצירת האובייקט מייצוגו, באובייקטים מורכבים. כך ניתן להשתמש באותו תהליך יצירה ליצירת אובייקטים שונים.
נשתמש כאשר:
|
|
Lazy initialization | "אתחול עצל" - טקטיקה המאפשרת שליטה על בזבוז משאבים, חישוב הזמן המתאים ליצירת האובייקט בפועל רק לזמן שחייבים אותו, תוך התחשבות בתהליכים השונים והכרעה איזה תהליך "יקר" יותר. | |
Object pool | שחרור משאבים על ידי מחזור אובייקטים שאינם בשימוש. | |
Prototype | הגדרת אבטיפוס של אובייקטים ויצירת אובייקטים חדשים כהעתק שלו.
נשתמש כאשר: המערכת צריכה להיות בלתי תלויה באופן בו פריטים נוצרים, מורכבים ומייצוגים, וגם מתקיים לפחות אחד מהתנאים מהבאים:
|
|
Singleton | הגדרת נקודת כניסה יחידה לאובייקט לשם הקצאת מופע יחיד של האובייקט בזיכרון.
נשתמש כאשר:
|
|
Multiton | יצירת מצב בו במחלקה יש רק מופעים בעלי שם (לא מצביעים), וסיפוק נקודת גישה גלובלית אליהם. | |
Resource acquisition is initialization | הבטחת תוחלת חיים נכונה של אובייקטים, לשם ניהול מושכל של המשאבים. |
תבניות מבנה
מטרתן של תבניות אילו היא להקל על עיצוב המערכת על ידי זיהוי דרך פשוטה לממש קשרים בין ישויות.
שם התבנית | תיאור | UML |
---|---|---|
Adapter | יצירת שיתוף פעולה בין מחלקות על ידי המרה נכונה בין הממשק המתקבל לממשק המצופה.
נשתמש כאשר:
|
|
Bridge | "גשר" - יצירת חוסר תלות בין ממשק למימוש, על ידי הפרדה מוחלטת ביניהם.
נשתמש כאשר:
|
|
Composite | גיבוש אובייקטים למבנה היררכי של עץ, אפשור התייחסות לאובייקטים כאובייקטים עצמאיים או באופן אחיד לצרוף של אובייקטים.
נשתמש כאשר נרצה שהלקוחות יוכלו להתעלם מההבדלים בין הרכבה של אובייקטים לאובייקטים בודדים, ויתייחסו לשניהם באופן אחיד. |
|
Decorator | הוספת אחריויות נוספות לאובייקט באופן דינמי תוך שמירה על אותו הממשק. Decorator משמש כחלופה גמישה לתת מחלקה כדי להרחיב פונקציונליות.
נשתמש כאשר:
|
|
Facade | מאפשר ממשק אחיד לאוסף של ממשקים בתת-מערכת. Facade מגדיר ממשק ברמה גבוהה יותר המאפשר שימוש קל בתת-מערכת.
נשתמש כאשר:
|
|
Flyweight | שימוש בשיתוף כדי לתמוך במספר אובייקטים כדי לחסוך בזיכרון.
יעילותו של Flyweight תלויה באיך ומתי משתמשים בה. נכון להשתמש בתבנית כאשר כל התנאים הבאים מתקיימים:
|
|
Proxy | מאפשר לשלוט בגישה לאובייקט אחר.
מתאים לשימוש כאשר במקום מצביע רגיל יש צורך במצביע רב תכליתי או מתוחכם לאובייקט. קיימות כמה Proxy סיטואציות בהן נכון להשתמש בתבנית:
|
תבניות התנהגות
כאשר מפתחים מערכת גדולה ישנו קושי בניתוח אינטראקציה בין אובייקטים, לכן עולה הצורך להגדיר סמכויות ולאפיין את אופי התקשורת בין הישויות שבה. תבניות התנהגות, עוסקות בבעיות אלו, בדומה לארגון, על ידי הגדרת הסמכויות הנדרשת והתקשורת בין הישויות. ירושה והרכבה עוזרים לתבניות התנהגותיות בהגדרת היחסים בין המחלקות.
שם התבנית | תיאור | UML |
---|---|---|
Chain of responsibility | מניעת קשר בין השולח של בקשה למקבל שלה על ידי כך שיותר מאובייקט אחד יוכל לטפל בבקשה. שרשור האובייקטים המקבלים והעברת הבקשה לאורך השרשרת עד שאובייקט מטפל בה.
נשתמש כאשר:
|
|
Command | כימוס של בקשה כאובייקט, ובצורה זו מאפשרת להעביר למקבלים בקשות שונות, להכניס בקשות לתור או לרשום אותן ללוג, ולתמוך בביטול פעולות.
נשתמש כאשר:
|
|
Interpreter | בהינתן שפה, מגדיר ייצוג של הדקדוק שלה יחד עם מפרש שמשתמש בייצוג כדי לפרש את המשפטים של השפה.
כאשר יש שפה לפענח, וניתן לייצג את השפה כעצי תחביר מופשטים (לדוגמה ביטוי רגולרי). התבנית תעבוד כאשר:
|
|
Iterator | דרך לגשת ברצף לאלמנטים באובייקט המורכב מאוסף של אלמנטים בלי לחשוף את המבנה הפנימי שלו.
נשתמש כאשר:
|
|
Mediator | מגדיר אובייקט שמכמס את האופן שבו אוסף של אובייקטים מתקשרים. התבנית תומכת בצימוד רפוי, בכך שאובייקטים לא מצביעים אחד לשני באופן ישיר, אלא למתווך (Mediator), ובכך ניתן לשנות את האינטראקציה שלהם באופן עצמאי.
נשתמש כאשר:
|
|
Memento | ללא פגיעה בכימוס, תפיסה וייחצון של המצב הפנימי של אובייקט, כך שהאובייקט יוכל להיות משוחזר למצב זה מאוחר יותר.
נשתמש כאשר חלק מה-state של האובייקט חייב להישמר, כדי לשחזר אותו בעבר וגם כאשר ממשק ישיר לקבלת ה-state הפנימי עלול לחשוף את המימוש ולפגוע בהכמסה. |
|
Null Object | משמש כברירת מחדל לאובייקט, ובכך מונע את הצורך לוודא שהאובייקט אינו null לפני שימוש בו. | |
Observer | מגדיר תלות של אחד לרבים בין אובייקטים, כך ש שכאשר אובייקט אחד משנה את מצבו, כל התלויים בו מיודעים על השינוי ומתעדכנים אוטומטית.
נשתמש כאשר:
|
|
Blackboard | Observer כללי המאפשר מספר קוראים וכותבים. המידע משותף לרוחב המערכת. | |
State | מאפשר לאובייקט לשנות את התנהגות כאשר מצבו הפנימי משתנה. האובייקט ישנה את המחלקה שבה הוא משתמש.
נשתמש כאשר:
|
|
Strategy | מגדיר משפחה של אלגוריתמים, מכמס כל אחד מהם, ומאפשר להחליף את השימוש בהם. ניתן לשנות את האלגוריתם באופן עצמאי בלי תלות במשתמשים במחלקה.
נשתמש כאשר:
|
|
Specification | צירוף לוגיקה עסקית בצורה בוליאנית (לא, או, וגם). | |
Template method | מגדיר שלד של אלגוריתם בפעולה, ומפנה חלק מן הצעדים לתת מחלקות. כך תת-מחלקות יכולות להגדיר מחדש צעדים מסוימים של האלגוריתם, ללא שינוי של המבנה שלו.
נשתמש כאשר:
|
|
Visitor | מייצג פעולה לביצוע על האלמנטים של מבנה האובייקט. בכך מאפשרת התבנית להגדיר פעולה חדשה ללא צורך לשנות את המחלקות של האלמנטים שעליהם היא מבוצעת.
נשתמש כאשר:
|
התבנית Inversion of control אשר מאפשרת הזרקה של אובייקטים מתאימים בשלב ההרצה משמשת כתבנית הבסיסית למערכת התשתית הנפוצה Spring.
קישורים חיצוניים
- Design Pattern – מדיה ומימושים בנושא תבניות עיצוב (באנגלית)
- Design Pattern Blog - בלוג עם הסברים מעמיקים ומעשיים לעבודה נכונה עם תבניות עיצוב (עברית)
- Inversion of Control
- דב זילברמן, Design Patterns, הסדרה "תבניות" וסרטונים נוספים
הערות שוליים
- ^ תבניות עיצוב למתחילים (Design patterns for dummies), ספר מאת ברברה פורצ'ייס, סטיבן הולצ'נר
- ^ ספר מאת ראלף ג'ונסון, אריק גאמה וריצ'רד הלם, Design Patterns: Elements of Reusable Object-Oriented Software
- ^ A Pattern Language: Towns, Buildings, Construction, by Christopher Alexander
- ^ Patterns versus antipatterns
- ^ מדריך לתבניות עיצוב וסוגן
27798591תבנית עיצוב