Table of Contents
בניית ארכיטקטורות תוכנה שחייבות לשרת מגוון גדל והולך של סוגי מכשירים - מסמארטפונים וטאבלטים למחשבים שולחניים ו-IoT משובצ - היא אחד האתגרים המתמשכים ביותר בהנדסה המודרנית.צוותים לעתים קרובות נאבקים לשמור על קודים כאשר כל פלטפורמה דורשת רכיבים ייחודיים של UI, מנגנוני אחסון נתונים או פרוטוקולים ברשת.תבנית המפעל ה-Atric מציעה פתרון מנוסח בקרב.
בסעיפים הבאים, אנו בודקים את תבנית המפעל האבלקטית בפירוט, לחקור את היתרונות קונקרטיים שלה עבור תמיכה רב-הדק, ללכת באמצעות יישום מציאותי, לדון במלכודות ושיטות הטובות ביותר שיכול לעשות או לשבור את הצלחתו בייצור.
הבנת תבנית המפעל
דפוס המפעל הפשטי הוא דפוס עיצוב בריא המספק ממשק ליצירת משפחות של אובייקטים קשורים או תלויים מבלי לציין את מעמדות קונקרטיים שלהם.במקום שיש מפעל יחיד אשר בונה סוג אחד של אובייקט, מפעל מופשט מגדיר שיטות לייצור כל האובייקטים השייכים למשפחה מסוימת של מוצר.קונקט תת-מעמדות של מפעל זה אז להחליט איזה כיתות מדויקות למיד.
התבנית משווה לעתים קרובות ליצרן רהיטים שמייצר כיסא, שולחן וספה קובע.אם אתה מסדר סט בסגנון ויקטוריאני, כל חתיכה חולקת את אותה גישה אסתטית ובנייה; אם אתה מסדר קבוצה בסגנון מודרני, החלקים יוצרים אוסף קוהרנטי אך שונה לחלוטין.הלקוח לעולם לא צריך לדעת אילו תכונות מסוימות של כיסא או שולחן בנויות - רק מכנה שיטות המפעל ומקבלים אובייקטים מובטחים לעבוד יחד עם קוד עיצוב:0 שלנו, כמו פלטפורמת עיצוב:
דפוס זה הופיע לראשונה בספר "Gang of Four" (GoF) המשפיע, (FLT:0Design Patterns: Elements of Reusable Object-Oriented SoftwareveFLT:1 (1994), והוא נשאר אבן הפינה של אדריכלות מוכוונת להתנגדות מאז.הרלוונטיות המתמשכת שלו נובעת מיכולתה להדוף את קוד הלקוחות מהכיתות קונקרטיות שהיא משתמשת, מה שהופך את המערכת הקלה ביותר להרחיב, ולתחזק יותר, ולקיים את הזמן.
היתרונות של תמיכה רב-הדק
כאשר היישום שלך חייב לרוץ על מספר קטגוריות מכשירים נפרדות - כל אחד עם גודל המסך שלו, שיטת קלט, מאפייני ביצועים, מערכת הפעלה - תבנית המפעל אבסטרקטי מספק יתרונות מעשיים כי באופן ישיר לשפר את איכות הקוד ואת הפרודוקטיביות של מפתחים.
שקיפות בפלטפורמות
מכיוון שהתבנית מאכיפת חוזה נוקשה לכל משפחה של מוצר, כל האובייקטים שנוצרו עבור פלטפורמה מסוימת מובטחים להיות תואמים.אתה אף פעם לא עולה עם מזהה מחווה מגע המיועד לנייד בטעות חוטף לתוך מטפל עכבר שולחני.עקב זה מקטין הפתעות בריצה ועושה בדיקה חוצה פלטפורמות ניתן לצפות יותר.
קוד ה-Competific Code
כל מפעל קונקרטי חי במודול או החבילה שלו.כל הקוד הקשור אליו, למשל, קרן Windows Show (WPF) מוכללת בתוך מערכת ההפעלה WindowsFactory.אם דרישה פלטפורמה משתנה - לדוגמה, מדריך בסגנון חזותי חדש - אתה משנה רק את המפעל ואת מוצריו.שאר היישום הוא ללא פגע.
תוספת משוחדת של סוגים חדשים של מכשירים
כאשר מופיעה קטגוריה חדשה של המכשיר (למשל, שעון חכם או טלפון מתקפל), אין צורך לקרוע את הקוד הקיים.אתה מיישם מפעל קונקרטי חדש ואת שיעורי המוצר שלו, ולהרשם אותו עם כל מנגנון התצורה שבו השימוש שלך (זריקת תלות, סביבה לוחמת משתנה, או דגל בונה).
שיפור יכולת
בדיקות יחידה הופכות פשוטות יותר מכיוון שניתן ליצור מפעלים ללעג, אשר מחזירים את מבחן כפול של כל מוצר.לדוגמה, ניתן לבנות משוב מהיר 3, המייצר רכיבים קלים, לא-ויזואליים ששיטת התקליטים מכנה במהירות ובבידוד, מתן משוב מהיר במהלך הפיתוח.
יצירת אובייקטים מרכזית
כל לוגיקה הבריאה מרוכזת במקום אחד לפלטפורמה.במקום מפוזרים בלוקים של FLT:4 לאורך בסיס הקוד שלך, אתה מסתמכ על אובייקט מפעל יחיד.המרכזיזציה הזו מקלה על אכיפת חששות ממושכים כגון כניסה, משאבה, או ניטור ביצועים ללא קוד לקוח מזוההה.
יישום התבנית באדריכלות תוכנה
למרות שניתן ליישם את תבנית המפעל האבלק בשפות רבות ופרדיגמות, השלבים הבסיסיים נשארים עקביים.ההליכה הבאה משתמשת בשחקן תקשורתי היפותטי חוצה כוכבי כדי להמחיש את התהליך.
שלב 1: Define אבסטרקטיות
החל על ידי זיהוי משפחות של אובייקטים היישום שלך צריך לתמוך במכשירים.עבור שחקן מדיה, ייתכן שתצטרך לוח הבקרה של תחבורה, ויזואליצר, ומנהל השמע. ליצור ממשק או מחלקה מופשטת עבור כל סוג המוצר.
// C#‑style pseudocode
public interface ITransportControl {
void Play();
void Pause();
void Seek(TimeSpan position);
}
public interface IVisualizer {
void Render(AudioData data);
}
public interface IPlaylistManager {
void AddTrack(Track track);
void RemoveTrack(int index);
IEnumerable<Track> GetTracks();
}
ממשקים אלה מגדירים את החוזה שכל יישום קונקרטי חייב לעקוב, להבטיח כי קוד הלקוח יכול אינטראקציה עם כל גרסה באמצעות ממשק API משותף.
שלב 2: Define the Pink Factory Interface
הבא, ליצור ממשק (או מחלקה מופשטת) המכריז על שיטות מפעל לכל משפחה של מוצר.
public interface IMediaPlayerFactory {
ITransportControl CreateTransportControl();
IVisualizer CreateVisualizer();
IPlaylistManager CreatePlaylistManager();
}
שימו לב כי סוגי ההחזר הם ממשקים מופשטים, לא כיתות קונקרטיות.הפשטה זו היא שמאפשרת ללקוח להישאר מחוספס מפרטי פלטפורמה.
שלב 3: יישום גורמי קידוד לכל פלטפורמה
עבור כל מכשיר מטרה או פלטפורמה, ליצור מחלקה במפעל קונקרטית שמילאה את כל שיטה, מיידית את המוצר של הפלטפורמה-appropriate. לדוגמה, שולחן העבודה יכול להחזיר את הפקדים המבוססים על WPF, בעוד MobileFactory מחזיר Swift או Jetpack Compose רכיבים:
public class DesktopMediaPlayerFactory : IMediaPlayerFactory {
public ITransportControl CreateTransportControl() => new DesktopTransportControl();
public IVisualizer CreateVisualizer() => new DesktopVisualizer();
public IPlaylistManager CreatePlaylistManager() => new DesktopPlaylistManager();
}
public class MobileMediaPlayerFactory : IMediaPlayerFactory {
public ITransportControl CreateTransportControl() => new MobileTransportControl();
public IVisualizer CreateVisualizer() => new MobileVisualizer();
public IPlaylistManager CreatePlaylistManager() => new MobilePlaylistManager();
}
שלב 4: תתקשרו למפעל ליישום
המפעל בדרך כלל נבחר על ידי ההפעלה בהתבסס על הסביבה בזמן ריצה.בחירה זו יכולה לקרות באמצעות קובץ תצורה, מיכל הזרקת תלותיות, או בדיקה פשוטה של הסביבה. ברגע שדוגמה במפעל זמינה, אתה מעביר אותו (או את המוצרים שלה) לחלקים של היישום כי צריך אותם. כי הקוד הלקוח הוא כתוב נגד ממשקים מופשטים לבד, אותו קוד יכול לרוץ על שולחן העבודה או נייד ללא סניף.
// Client code (e.g., main window)
public class MediaPlayerWindow {
private readonly ITransportControl _transport;
private readonly IVisualizer _visualizer;
private readonly IPlaylistManager _playlist;
public MediaPlayerWindow(IMediaPlayerFactory factory) {
_transport = factory.CreateTransportControl();
_visualizer = factory.CreateVisualizer();
_playlist = factory.CreatePlaylistManager();
}
public void Initialize() {
_transport.Play();
_visualizer.Render(...);
// etc.
}
}
טכניקה זו - הנקראת לעתים קרובות הזרקת התלות - שומרת על היישום מודולרי מאוד.אם סוג חדש של מכשיר מופיע, אתה כותב מפעל חדש ושיעורי מוצר, לעדכן את שורש הרכב, ואתה נעשה.
יישומים אמיתיים ומסגרות
תבנית המפעל הפשטנית אינה סקרנות אקדמית; היא משמשת באופן פעיל בפרויקטים מרכזיים של תוכנה.לדוגמה, (FLT:0)DirectusFLT:1, CMS ללא קוד פתוח, ממנת ממשקים מופשטים עבור שכבת הפשטות של הנתונים שלה, ומאפשרת לו לתמוך במנועי מסד נתונים שונים (SQLite, PostgreSQL), MySQL) עם שינויים קוד מינימליים.
בדומה לכך, Javaster Window Toolkit (AWT) משתמש בארכיטקטורה עמיתים שהיא בעצם מפעל אבסטרקטי: The Javasteral Window Toolkit 10 בכיתה יוצר עמיתים ספציפיים פלטפורמה עבור חלונות, כפתורים ותפריטים.כאשר יישום Java פועל על Windows, macOS, או Linux, מפעל ערכת הכלים הבטון של הכלי קונקרטי מייצר את השליטה הילידים בצורה חלקה.
מסגרות סלולריות של קרוס-platform כמו Flutter ו- React Native גם מהדהדות את הרעיון של המפעל הפשט, אם כי הם בדרך כלל משתמשים אדריכלות עץ widget.למרות זאת, מושג הליבה של הגדרת משפחה של רכיבים UI אשר מאוחר יותר ניתן על ידי מנועי פלטפורמה ספציפית נשאר אותו הדבר.
קישור בין מפעלים מופשטים לבין דליקות תלותיות
מסגרות יישום מודרניות רבות (ASP.NET Core, Spring, Dagger) מספקות פתרון אוטומטי באמצעות מיכלי הזרקת התלות. בעוד מיכלים אלה מחליפים לעתים קרובות את הצורך לכתוב שיעורי מפעל מפורשים עבור כל תרחיש, דפוס המפעל הפשט עדיין מאיר כאשר אתה צריך ליצור משפחות של אובייקטים הקשורים זה - משהו פשוט DI לא יכול לאכוף. במקרים כאלה, אתה יכול לרשום מפעל ולתת את המכולה בדוגמה הנכונה על בסיס פרמטר (למשל, הפעלה).
אתגרים ומלכודות
אין דפוס הוא כדור כסף.תבנית המפעל הפשט מציגה כמה מורכבות שצוותי הפיתוח חייבים לטפל בו בכוונה.
מספר גדל והולך של
כל משפחה חדשה של מוצר וכל פלטפורמה חדשה מכפילה את מספר הממשקים, מפעלים קונקרטיים, ואת שיעורי המוצר.ללא ארגון פרויקט זהיר, בסיס הקוד יכול להיות מחוספס. Mitigate זה על ידי אכיפת שמות קפדניים או אריזה, ועל ידי שמירה על ממשקי המוצר ממוקד וקטן.
קשה כשמשפחות המוצר צומחות
אם מוצר חדש (למשל, נספח) חייב להיות נוסף לשחקן התקשורת, כל מפעל בטון קיים חייב ליישם את השיטה החדשה, גם אם המוצר הזה אינו רלוונטי על פלטפורמות מסוימות.זה יכול לשבור את עקרון Open/Closed אם לא תוכנן בקפידה.פתרון אחד הוא להשתמש במפעל מופשט נפרד עבור כל משפחה של מוצרים אופציונליים, או לספק ברירת מחדל (noop) ביישום בסיס מעמדי.
אפשרויות לOverhead
בחירת המפעל הנכון בריצה לעתים קרובות מוסיף כמות קטנה של לוגיקה מותנית (החלפת או אם שרשרת) בסטארט-אפ. בעוד רשלנות ברוב היישומים, זה יכול להפוך לבעיה תחזוקה אם קריטריונים הבחירה להיות מורכב - לדוגמה, גורם במודל המכשיר, גרסת ההפעלה, ודחיסות המסך. שקול באמצעות תבנית רישום או שולחן מבט כדי לשמור על קוד הבחירה נקי.
בדיקות רבות
אם הבקשה שלך חייבת לתמוך, למשל, שלוש פלטפורמות וארבע משפחות מוצר, יש לך עכשיו 12 יישומי מוצר בתוספת שלושה מפעלים.בדיקה כל שילוב ביסודיות יכולה להיות זמן-הנחה. עדיפויות בדיקות את הממשקים מופשטים עם לעג, ולבצע בדיקות אינטגרציה עבור כל מפעל קונקרטי בנפרד.
הפרקטיקה הטובה ביותר ליישום
כדי להפיק את המרב מתבנית המפעל הפשט כאשר בניית תמיכה רב-הדקית, בצע את ההנחיות הללו.
- (FLT:0)Start withפשטות המשקפות הבדלים אמיתיים של פלטפורמה.Res.veFLT) 1 אל תייצר מפעל לכל שליטה קטנה של UI; אובייקטים הקשורים לקבוצה שבאמת משתנים יחד (למשל, מבנה ניווט, שיטות קלט, התמדה של נתונים).
- (FLT:0) לשמור על ממשקי המוצר מינימלי.FLT:1 כל ממשק צריך לחשוף רק את השיטות שקוד הלקוחות באמת צריך.שיטות נוספות מחייבות כל מוצר קונקרטי ליישם לוגיקה מיותרת.
- (FLT:0) הזרקת התלות של ה-Use לספק למפעל.Build.cioFLT:1) להימנע ממפעלים סטטיים או ממשתנים גלובליים.
- (FLT:0) דרישות ברירת מחדל שבו ניתן.BuildFLT:1; אם פלטפורמה חסרה יכולת מסוימת (למשל, ויזואליצר שולחני המשתמש האצה GPU), מפעל בסיס יכול לספק מוצר נופל.
- חברי הצוות צריכים להבין במהירות אילו מוצרים שייכים למשפחה ומה הקריטריונים מנחים את הקמת מפעל קונקרטי חדש.
- (FLT:0) מינוף מערכת הבנייה או CI /CD כדי לבדוק את כל שילובי הפלטפורמה.earph:1 גם אם אתה לא יכול להפעיל כל מבחן על כל מכשיר, בדיקות זמן מול ממשקים מופשטים יתפוסו פגמים מוקדם.
מסקנה
דפוס המפעל הפשטני נשאר אחד הכלים האמינו ביותר בתיבת הכלים של ארכיטקט התוכנה להשגת תמיכה רבת-העתית בר-ממדית בר-ממדית, על ידי קידוד הלקוחות של יישום פלטפורמה קונקרטית, הוא מאפשר לצוותים להוסיף סוגים חדשים של מכשירים מבלי להפריע פונקציונליות קיימת, שומר על לוגיקה ספציפית פלטפורמה מבודדת, ואכיפת עקביות על פני כל משפחת המוצר.
בין אם אתה בונה מערכת ניהול תוכן כמו FLT:0DirectusFLT ( 1:1) אשר חייב לתמוך במספר החזרי אחסון, או יישום C-platform GUI אשר הופך את הילידים על כל מערכת הפעלה, המפעל המינהל מספק בסיס נקי ומוכח. בשילוב עם אסטרטגיות בדיקה מוצקות ותיעוד ברור, זה ישמור את האדריכלות שלך חזק ומתאימת זמן רב לאחר הגל הבא של התקנים מגיע.
(בקריאה נוספת, ניתן למצוא את ההסבר הקנון בספר GoF המקורי, ומשאבים מקוונים כגון FLT:0refactoring GuruveFLT:1) להציע דוגמאות ברורות בשפות מרובות.בנוסף, המאמר:2Wikipedia על תבנית המפעל הפשט 3FLT מספק סקירה טכנית מצוינת עם דיאגרמות UML.