בהמשך לטיפ הקודם,
אני מרגיש שקצת רימיתי בכתיבה של הInterfaceים של הSyntax, כי לא כל כך ברור איך חשבתי על הקשרים הנכונים בין הSyntaxים.
למען האמת, כשכתבתי את הטיפ, ניסיתי להתאים את הקוד כך שהוא יעבוד, אבל לא כל כך היה ברור למה הוא עובד.
לאחר מכן חשבתי על זה ואפשר להסתכל על הבעיה בצורה אחרת:
ננסה לממש את מה שכתבתי בסוף הטיפ הקודם – שאפשר לקרוא לWithDefaultValue לכל היותר פעם אחת לעמודה, ולMakePrimaryKey פעם אחת לטבלה.
אנחנו מעוניינים שתמיד הפעולה הראשונה שתקרה היא WithColumn, לאחר מכן אנחנו מרשים שיקרו הפעולות WithColumn, WithDefaultValueוMakePrimaryKey, אבל עם הסייגים הבאים:
- אפשר לקרוא לMakePrimaryKey רק פעם אחת
- בין כל שני WithColumn אפשר לקרוא לWithDefaultValue רק פעם אחת
מדובר בעצם בשפה הנוצרת מעל הא”ב
$ { \text{WithColumn}, \text{MakePrimaryKey}, \text{WithDefaultValue} } $
עם החוקים שרשמנו מעלה.
אם נסמן $ a = \text{WithColumn}$, $ b =\text{MakePrimaryKey}$, $ c =\text{WithDefaultValue}$, אז השפה היא כל המילים שמתחילות ב$ a$, מכילות $ b$ לכל היותר פעם אחת, ומכילות $ c$ לכל היותר פעם אחת בין כל שני $ a$ים.
לשפה הזו אפשר לבנות אוטומט מתאים:
כאשר כל המצבים פה הם מצבים מקבלים, ובמעברים שלא מופיעה בהם אות מסוימת, מדובר במעבר למצב מלכודת, כלומר מצב לא חוקי. (כלומר אם כתבנו $ b $ פעמיים במילה או $ c$ יותר מפעם אחת בין שני $ a $ים, לא נוכל לתקן את המילה)
בהנחה שאין טעויות באוטומט, נוכל לתרגם זאת לממשקים:
|
|
איך התרגום התבצע? פשוט יצרנו ממשק לכל מחלקה. כעת דאגנו ששימוש בפונקציה המתאימה (כלומר הוספת אות מהא"ב), יוביל אותנו למצב המתאים לפי האוטומט.
לדוגמה, ב$ Q_3 $ יש מעבר ל$ Q_5 $ אם מקבלים $ c $, אבל מעבר ל$ Q_6 $ אם מקבלים $ a $.
לכן בממשק IQ3<T> כשאנחנו קוראים לפונקציהWithDefaultValue (שאותה מייצגת האות $ c $), אנחנו דואגים להחזיר IQ5. לעומת זאת, כשאנחנו קוראים לWithColumn (שאותה מייצגת האות $ a $), אנחנו דואגים להחזיר IQ6.
הדבר הזה מאפשר לנו לאכוף את מה שרצינו: בהינתן הExtension Method הבא:
|
|
כל החוקים שרצינו לאכוף נאכפים:
|
|
ממש מגניב!
המשך יום צף טוב!