דפוס הפקודה בג'אווה

1. סקירה כללית

דפוס הפקודה הוא דפוס עיצוב התנהגותי והוא חלק מרשימת דפוסי העיצוב הרשמית של GoF. במילים פשוטות, התבנית מתכוונת לעטוף באובייקט את כל הנתונים הנדרשים לביצוע פעולה נתונה (פקודה), כולל איזו שיטה לקרוא, טיעוני השיטה והאובייקט אליו שייכת השיטה.

מודל זה מאפשר לנו לפרק אובייקטים שמייצרים את הפקודות מהצרכנים שלהם, לכן זו הסיבה שהדפוס מכונה בדרך כלל דפוס הצרכן של היצרן.

במדריך זה נלמד כיצד ליישם את דפוס הפקודה ב- Java על ידי שימוש בגישות מונחות עצמים והן בגישות פונקציונליות, ונראה באילו מקרי שימוש זה יכול להיות שימושי.

2. יישום מונחה עצמים

ביישום קלאסי, דפוס הפקודה דורש יישום ארבעה מרכיבים: הפקודה, המקבל, המזמין והלקוח.

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

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

לכן, עלינו לפרק את היישום לארבעת המרכיבים שהוזכרו לעיל.

2.1. כיתות פיקוד

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

כדי לקבל מושג מדויק יותר על האופן שבו אובייקטים של פקודה עובדים, נתחיל לפתח שכבת פקודה פשוטה הכוללת ממשק אחד בלבד ושתי יישומים:

ממשק ציבורי @FunctionalInterface TextFileOperation {מחרוזת ביצוע (); }
מחלקה ציבורית OpenTextFileOperation מיישמת TextFileOperation {private TextFile textFile; // constructors @Override public מחרוזת ביצוע () {return textFile.open (); }}
מחלקה ציבורית SaveTextFileOperation מיישמת את TextFileOperation {// אותו שדה ובונה כנ"ל @Override public String execute () {return textFile.save (); }} 

במקרה זה, TextFileOperation ממשק מגדיר את ה- API של אובייקט הפקודה ואת שתי היישומים, OpenTextFileOperation ו SaveTextFileOperation, לבצע את הפעולות הקונקרטיות. הראשון פותח קובץ טקסט, ואילו האחרון שומר קובץ טקסט.

ברור לראות את הפונקציונליות של אובייקט פקודה: ה- TextFileOperation פקודות לצרף את כל המידע הנדרש לפתיחה ושמירה של קובץ טקסט, כולל אובייקט המקלט, השיטות להתקשרות והוויכוחים (במקרה זה, אין צורך בטיעונים, אך הם יכולים להיות).

כדאי להדגיש זאת הרכיב המבצע את פעולות הקבצים הוא המקלט (ה- TextFile למשל).

2.2. כיתת המקלט

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

במקרה זה עלינו להגדיר כיתת מקלט שתפקידה לדגמן TextFile חפצים:

מחלקה ציבורית TextFile {שם מחרוזת פרטי; // בונה ציבורי מחרוזת פתוחה () {להחזיר "קובץ פתיחה" + שם; } שמירת מחרוזות ציבורית () {להחזיר "שמירת קובץ" + שם; } // שיטות קובץ טקסט נוספות (עריכה, כתיבה, העתקה, הדבקה)} 

2.3. כיתת הפוקר

מזמין הוא אובייקט ש יודע כיצד לבצע פקודה נתונה אך אינו יודע כיצד הופעלה הפקודה. זה יודע רק את ממשק הפקודה.

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

בדוגמה שלנו, מתברר כי חייב להיות רכיב נוסף האחראי על הפעלת אובייקטי הפקודה וביצועם באמצעות הפקודות. לבצע() שיטה. כאן בדיוק נכנסת לתפקיד מחלקת המזמינים.

בואו נסתכל על יישום בסיסי של המזמין שלנו:

מחלקה ציבורית TextFileOperationExecutor {private final רשימה textFileOperations = ArrayList חדש (); מחרוזת ציבורית executeOperation (TextFileOperation textFileOperation) {textFileOperations.add (textFileOperation); להחזיר textFileOperation.execute (); }}

ה TextFileOperationExecutor הכיתה היא פשוט א שכבה דקה של הפשטה שמנתקת את אובייקטי הפקודה מהצרכנים שלהם וקוראת לשיטה המקופלת בתוך ה- TextFileOperation חפצי פיקוד.

במקרה זה, המחלקה שומרת גם את אובייקטי הפקודה ב- a רשימה. כמובן, זה לא חובה ביישום הדפוס, אלא אם כן עלינו להוסיף שליטה נוספת בתהליך הביצוע של הפעולות.

2.4. מחלקת הלקוחות

לקוח הוא אובייקט ש שולט בתהליך ביצוע הפקודה על ידי ציון אילו פקודות לבצע ובאילו שלבים של התהליך לבצע אותן.

לכן, אם אנו רוצים להיות אורתודוקסים עם ההגדרה הפורמלית של התבנית, עלינו ליצור מעמד לקוח על ידי שימוש בטיפוסי רָאשִׁי שיטה:

main static public ריק (String [] args) {TextFileOperationExecutor textFileOperationExecutor = חדש TextFileOperationExecutor (); textFileOperationExecutor.executeOperation (OpenTextFileOperation חדש (TextFile חדש ("file1.txt")))); textFileOperationExecutor.executeOperation (SaveTextFileOperation חדש (TextFile חדש ("file2.txt"))); } 

3. יישום אובייקט פונקציונלי

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

מג'אווה 8 נוכל להשתמש בגישה פונקציונלית של אובייקט, המבוססת על ביטויים למבדה והפניות לשיטה, ל- הפוך את הקוד לקומפקטי יותר ופחות מילולי.

3.1. שימוש בביטויי למבדה

כמו ה TextFileOperation ממשק הוא ממשק פונקציונלי, אנחנו יכולים להעביר חפצי פיקוד בצורת ביטויים למבדה למזמין, ללא צורך ליצור את TextFileOperation מקרים במפורש:

TextFileOperationExecutor textFileOperationExecutor = חדש TextFileOperationExecutor (); textFileOperationExecutor.executeOperation (() -> "פתיחת קובץ file1.txt"); textFileOperationExecutor.executeOperation (() -> "שמירת קובץ file1.txt"); 

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

למרות זאת השאלה עדיין עומדת: האם גישה זו טובה יותר בהשוואה לזו המכוונת לעצמים?

ובכן, זה מסובך. אם אנו מניחים שקוד קומפקטי יותר פירושו קוד טוב יותר ברוב המקרים, אז אכן כך.

ככלל אצבע, עלינו להעריך על בסיס שימוש לכל מקרה מתי לנקוט בביטויים למבדה.

3.2. שימוש בהפניות לשיטה

באופן דומה, אנו יכולים להשתמש בהפניות לשיטה עבור העברת חפצי פקודה למזמין:

TextFileOperationExecutor textFileOperationExecutor = חדש TextFileOperationExecutor (); TextFile textFile = FileFile חדש ("file1.txt"); textFileOperationExecutor.executeOperation (textFile :: open); textFileOperationExecutor.executeOperation (textFile :: save); 

במקרה זה, היישום הוא קצת יותר מילולית מזה שמשתמש במבשרותכפי שעלינו עדיין ליצור את TextFile מקרים.

4. מסקנה

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

כרגיל, כל דוגמאות הקוד המוצגות במדריך זה זמינות ב- GitHub.