ממשק CLI למנהל המערכת
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 103 מתוך 107.
אתגר
קלבואו נבנה ממשק שורת פקודה למערכת ניהול הספרייה שלנו באמצעות דפוס הפקודה! תיצרו CLI שמעבד פקודות מנהל כמו הוספת ספרים, רישום משתמשים וניהול פעולות השאלה: הכול באמצעות ארכיטקטורה נקייה וניתנת להרחבה.
תארגנו את הקוד שלכם בשישה קבצים:
book.go: המבנהBookשלכם, עם תגיות JSON עבורID,Title,Author,ISBNו-Available. כללו את הבנאיNewBook.user.go: המבנהUserשלכם, עם תגיות JSON עבורID,Name,Emailו-BorrowedBooks. כללו את הבנאיNewUser.library.go: המבנהLibraryשלכם עם מפות עבור ספרים ומשתמשים, יחד עם המתודותAddBook,AddUser,Borrowו-Returnמהשיעורים הקודמים.commands.go: כאן דפוס הפקודה מתעורר לחיים! הגדירו ממשקCommandעם מתודתExecuteשמקבלת*Libraryו-[]stringכארגומנטים, ומחזירה תוצאה מסוג string. לאחר מכן, ממשו את מבני הפקודות האלה:AddBookCommand: מצפה ל-4 ארגומנטים: מזהה, כותרת, מחבר, ISBN. מוסיפה את הספר ומחזירהBook added: [title]AddUserCommand: מצפה ל-3 ארגומנטים: מזהה, שם, דוא"ל. מוסיפה את המשתמש ומחזירהUser added: [name]BorrowCommand: מצפה ל-2 ארגומנטים:userID,bookID. מחזירהBorrowed: [bookID]במקרה של הצלחה, אוError: [message]במקרה של כישלוןReturnCommand: מצפה ל-2 ארגומנטים:userID,bookID. מחזירהReturned: [bookID]במקרה של הצלחה, אוError: [message]במקרה של כישלוןListBooksCommand: לא מקבלת ארגומנטים. מחזירה את המזהה והכותרת של כל ספר, כל אחד בשורה נפרדת ובתבנית[id]: [title], אוNo booksאם הרשימה ריקה (מיינו את הספרים לפי מזהה)
אם פקודה מקבלת מספר לא מספיק של ארגומנטים, החזירו
Error: insufficient argumentscli.go: צרו מבנהCLIשמכיל מצביע ל-Libraryומפה של שמות פקודות למימושיCommand. בנו:- בנאי
NewCLIשמאתחל את ה-CLI עם ספרייה ורושם את כל הפקודות:addbook,adduser,borrow,return,listbooks - מתודת
Runשמקבלת מחרוזת קלט, מנתחת אותה באמצעותstrings.Fields, מחפשת את הפקודה ומבצעת אותה. החזירוNo command providedעבור קלט ריק, אוUnknown command: [name]עבור פקודות לא מוכרות
- בנאי
main.go: צרו ספרייה ו-CLI, ואז עבדו את הפקודות מהקלט. קראו את מספר הפקודות, ואז קראו כל מחרוזת פקודה בשורה נפרדת. עבור כל פקודה, קראו ל-Runוהדפיסו את התוצאה.
הקלטים הבאים יסופקו:
- מספר הפקודות
- כל פקודה כמחרוזת שלמה בשורה משלה
לדוגמה, בהינתן:
6
addbook B001 Go-Programming Alan-Donovan 978-0134190440
addbook B002 Clean-Code Robert-Martin 978-0132350884
adduser U001 Alice alice@test.com
borrow U001 B001
listbooks
borrow U001 B001הפלט שלכם צריך להיות:
Book added: Go-Programming
Book added: Clean-Code
User added: Alice
Borrowed: B001
B001: Go-Programming
B002: Clean-Code
Error: book not availableובהינתן:
4
listbooks
addbook B100 Design-Patterns Gang-of-Four 978-0201633610
listbooks
invalidcmd testהפלט שלכם צריך להיות:
No books
Book added: Design-Patterns
B100: Design-Patterns
Unknown command: invalidcmdובהינתן:
5
adduser U001 Bob bob@email.com
borrow U001 B001
addbook B001 Golang-Guide John-Smith 123-456
borrow U001 B001
return U001 B001הפלט שלכם צריך להיות:
User added: Bob
Error: book not found
Book added: Golang-Guide
Borrowed: B001
Returned: B001שימו לב שה-CLI לא צריך להכיר את הפרטים של כל פעולה. הוא פשוט מחפש את הפקודה ומעביר אליה את הביצוע. כך הוספת פקודות חדשות פשוטה כמו יצירת מבנה חדש שמממש את הממשק Command ורישומו ב-CLI!
נסו בעצמכם
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// קראו את מספר הפקודות
var n int
fmt.Scanln(&n)
// צרו סורק לקריאת שורות שלמות
scanner := bufio.NewScanner(os.Stdin)
// TODO: צרו Library חדשה
// TODO: צרו CLI חדש עם הספרייה
// TODO: עבדו כל פקודה
// עבור כל אחת מ־n הפקודות:
// - קראו את שורת הפקודה באמצעות scanner.Scan() ו־scanner.Text()
// - הריצו את הפקודה דרך ה־CLI
// - הדפיסו את התוצאה
_ = scanner // הסירו את השורה הזאת כשתשתמשו ב־scanner
}
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP ב-Go
קבצים חיצונייםסביבת העבודה והמודולים של Goחבילות וייבואשמות מיוצאים לעומת שמות לא מיוצאיםמבוא ל-OOP ב-GoStructs כמחלקותהגדרת מתודות עבור Structsמקבלי Pointer לעומת Valueאתחול Structפונקציות Constructorחזרה – מחשבון פשוט4ממשקים
מבוא לממשקיםמימוש משתמעממשק כחוזהממשק ריק (any)אימות טיפוסמתג טיפוסיםהרכבת ממשקיםממשקי Stringer ו-Errorסיכום – מחשבון צורות7כימוס
שדות מיוצאים לעומת שדות לא מיוצאיםכימוס ברמת החבילהמתודות Getter ו-Setterהסתרת מידע ב-Goסיכום – רשומות תלמידים10Generics (Go 1.18 ומעלה)
מבוא ל־Genericsפרמטרים של טיפוסיםאילוצי טיפוסיםמבנים גנרייםפתרון עוקף למתודות גנריותסיכום – אוסף גנרי2העמקה בסוגים וב-Structs
סוגים בסיסיים ומורכביםהגדרות של סוגים מותאמים אישיתתגיות StructStructs אנונימייםStructs מקונניםערכי אפס וברירות מחדלסיכום – ספר אנשי קשר5קומפוזיציה במקום ירושה
למה ב-Go אין ירושהיסודות הטמעת Structקידום מתודותהטמעת כמה Structsהטמעה לעומת אגרגציההסתרת מתודות מוטמעותסיכום – היררכיית עובדים8טיפול בשגיאות ו-OOP
ממשק errorסוגי שגיאות מותאמים אישיתעטיפת שגיאות (fmt.Errorf)שגיאות Sentinelerrors.Is() ו-errors.As()Panic, Defer ו-Recoverסיכום – מנתח קבצים11ספרייה סטנדרטית ותכנות מונחה עצמים
io.Reader ו-io.Writersort.Interfaceהממשק fmt.Stringerencoding/json עם מבניםהממשק http.Handlerסיכום – מודלים של REST API3מצביעים וזיכרון
יסודות המצביעים ב-Goמצביעים למבניםהעברה לפי ערך לעומת לפי הפניההפונקציה new()איסוף אשפה ב-Goסיכום - בונה רשימה מקושרת6פולימורפיזם ב-Go
פולימורפיזם באמצעות ממשקיםטיפוס ברווז ב-Goכללי התאמה לממשקאוספים פולימורפייםהזרקת תלויותסיכום - מעבד תשלומים9מקביליות ו-OOP
יסודות GoroutinesChannels ותקשורתChannel עם חוצץ לעומת ללא חוצץפקודת Selectsync.Mutex ו-sync.RWMutexsync.WaitGroupתכנון Struct בטוח לשימוש במקבילסיכום - מאגר עובדים12מושגים מתקדמים בתכנות מונחה עצמים
דפוס האפשרויות הפונקציונליותדפוס Builder ב-Goשרשור מתודותכינויי טיפוסים לעומת הגדרותיסודות Reflectionסקירה כללית של יצירת קוד15פרויקט: ניהול ספרייה
סקירה כללית ומבנה הפרויקטמבני נתונים של ספרים ומשתמשיםתרגלו בעצמכם: קומפיילר Go אונליין