תכנות מטאוגרפי בגרובי

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

Groovy היא שפת JVM דינמית ועוצמתית הכוללת תכונות רבות כמו סגירות ותכונות.

במדריך זה נחקור את המושג מטא-תכנות בגרובי.

2. מהי מטא-תכנות?

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

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

3. תכנות תכנות זמן ריצה

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

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

3.1. נכס חסר

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

ראשית, בוא נכתוב עוֹבֵד כיתה עם כמה מאפיינים:

class שכיר {String firstName מחרוזת שם משפחה int age}

שנית, ניצור עוֹבֵד התנגד ונסה להציג נכס לא מוגדר כתובת. כתוצאה מכך, זה יזרוק את חסר נכס נכס:

עובד עובד = עובד חדש (שם ראשון: "נורמן", שם משפחה: "לואיס") println emp.address 
groovy.lang.MissingPropertyException: אין נכס כזה: כתובת למחלקה: com.baeldung.metaprogramming. עובד

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

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

def propertyMissing (String propertyName) {"נכס '$ propertyName' אינו זמין"}
לטעון emp.address == "כתובת 'נכס' אינה זמינה"

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

def propertyMissing (String propertyName, propertyValue) {println "לא יכול להגדיר $ propertyValue - המאפיין '$ propertyName' אינו זמין"}

3.2. שיטה מתגעגע

ה שיטה מתגעגע שיטה דומה ל- נכס חסר. למרות זאת, שיטה מתגעגע מיירט קריאה לכל שיטה חסרה, ובכך נמנע מ- MissingMethodException.

בואו ננסה לקרוא ל getFullName שיטה על עוֹבֵד לְהִתְנַגֵד. כפי ש getFullName חסר, הביצוע יזרוק את MissingMethodException בזמן ריצה:

נסה לתפוס את {emp.getFullName ()} (MissingMethodException e) שיטת {println "לא מוגדרת"}

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

def methodMissing (String methodName, def methodArgs) {"השיטה '$ methodName' אינה מוגדרת"}
לטעון emp.getFullName () == "השיטה 'getFullName' אינה מוגדרת"

3.3. ExpandoMetaClass

גרובי מספק א metaClass נכס על כל שכבותיו. ה metaClass נכס מתייחס למופע של ExpandoMetaClass.

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

ראשית, בואו נוסיף את החסר כתובת רכוש ל עוֹבֵד בשיעור באמצעות metaClass תכונה:

Employee.metaClass.address = ""
עובד עובד = עובד חדש (שם ראשון: "נורמן", שם משפחה: "לואיס", כתובת: "ארה"ב") טוען כי emp.address == "ארה"ב"

אם נמשיך הלאה, בואו נוסיף את הנעדרים getFullName שיטה ל עוֹבֵד אובייקט מחלקה בזמן ריצה:

emp.metaClass.getFullName = {"$ lastName, $ firstName"}
לטעון emp.getFullName () == "לואיס, נורמן"

באופן דומה, אנו יכולים להוסיף קונסטרוקטור ל- עוֹבֵד שיעור בזמן הריצה:

Employee.metaClass.constructor = {מחרוזת firstName -> עובד חדש (firstname: firstName)}
עובד נורמן = עובד חדש ("נורמן") טוען norman.firstName == "Norman" טוען norman.lastName == null

כמו כן, אנו יכולים להוסיף סטָטִי שיטות באמצעות metaClass.static.

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

לדוגמה, בואו נוסיף a לְנַצֵל שיטה ל חוּט מעמד:

String.metaClass.capitalize = {String str -> str.substring (0, 1) .toUpperCase () + str.substring (1)}
טוענים "נורמן". capitalize () == "נורמן"

3.4. הרחבות

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

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

לדוגמא, בוא נכתוב א BasicExtension כיתה להוסיף א getYearOfBirth שיטה ל עוֹבֵד מעמד:

class BasicExtensions {static int getYearOfBirth (עובד שכיר) {return Year.now (). value - self.age}}

כדי לאפשר את BasicExtensions, נצטרך להוסיף את קובץ התצורה ב- META-INF / שירותים מדריך הפרויקט שלנו.

אז בואו נוסיף את org.codehaus.groovy.runtime.ExtensionModule קובץ עם התצורה הבאה:

moduleName = core-groovy-2 moduleVersion = 1.0-SNAPSHOT extensionClasses = com.baeldung.metaprogramming.extension.BasicExtensions

בואו נאמת את getYearOfBirth השיטה שנוספה ב עוֹבֵד מעמד:

גיל def = 28 def צפוי YearOfBirth = Year.now () - גיל עובד עובד = עובד חדש (גיל: גיל) טוען emp.getYearOfBirth () == צפוי YearOfBirth.value

באופן דומה, להוסיף סטָטִי בשיטות בכיתה, נצטרך להגדיר מחלקת הרחבה נפרדת.

למשל, בואו נוסיף a סטָטִי שיטה getDefaultObj שלנו עוֹבֵד מעמד על ידי הגדרה הרחבה של עובדים סטטיים מעמד:

class StaticEmployeeExtension {static Employee getDefaultObj (עובד עצמי) {להחזיר עובד חדש (firstName: "firstName", lastname: "lastName", גיל: 20)}}

לאחר מכן, אנו מאפשרים את StaticEmployeeExtension על ידי הוספת התצורה הבאה ל- ExtensionModule קוֹבֶץ:

staticExtensionClasses = com.baeldung.metaprogramming.extension.StaticEmployeeExtension

עכשיו, כל מה שאנחנו צריכים זה לבדוק את שלנו סטָטִיgetDefaultObj שיטה על עוֹבֵד מעמד:

לטעון Employee.getDefaultObj (). firstName == "firstName" להצהיר Employee.getDefaultObj (). lastName == "lastName" טוען Employee.getDefaultObj (). גיל == 20

בדומה לכך, באמצעות הרחבות, אנו יכולים להוסיף שיטה לשיעורי Java שהורכבו מראש כמו מספר שלם ו ארוך:

ריק סטטי ציבורי printCounter (שלם עצמי) {תוך (עצמי> 0) {println עצמי עצמי -} החזר עצמי} טען 5. printCounter () == 0 
ריבועי סטטי ציבורי ארוך (עצמי עצמי ארוך) {החזר עצמי * עצמי} טוען 40l.square () == 1600l 

4. תכנות מטא-תכנות בזמן

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

בואו נדון בכמה מההערות שהן שימושיות למדי בגרובי להפחתת קוד הדוד. רבים מהם זמינים ב groovy.transform חֲבִילָה.

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

4.1. @ToString

ה @ToString ההערה מוסיפה יישום ברירת המחדל של ה- toString שיטה לשיעור בזמן קומפילציה. כל מה שאנחנו צריכים זה להוסיף את ההערה לכיתה.

לדוגמה, בואו נוסיף את @ToString ביאור שלנו עוֹבֵד מעמד:

שכבת @ TooString עובד {מזהה ארוך מחרוזת שם פרטי מחרוזת שם גיל}

כעת ניצור אובייקט של ה- עוֹבֵד class ולאמת את המחרוזת שהוחזרה על ידי ה- toString שיטה:

עובד שכיר = עובד חדש () עובד.יד = עובד 1. FirstName = "נורמן" עובד.לאסטנאם = "לואיס" עובד.גיל = 28 טוען עובד.טו מחרוזת () == "com.baeldung.metaprogramming. עובד (1, נורמן, לואיס, 28) "

אנו יכולים גם להכריז על פרמטרים כגון לא כולל, כולל, includePackage ו להתעלם מאפסים עם @ToString כדי לשנות את מחרוזת הפלט.

לדוגמא, בוא נכלול תְעוּדַת זֶהוּת ו חֲבִילָה מהמחרוזת של אובייקט העובד:

@ToString (includePackage = false, excludes = ['id'])
לטעון את העובד. toString () == "עובד (נורמן, לואיס, 28)"

4.2. @TupleConstructor

להשתמש @TupleConstructor ב- Groovy כדי להוסיף קונסטרוקטור פרמטריאלי בכיתה. ביאור זה יוצר קונסטרוקטור עם פרמטר לכל מאפיין.

לדוגמא, בואו נוסיף @TupleConstructor אל ה עוֹבֵד מעמד:

שכבת @TupleConstructor עובד {מזהה ארוך מחרוזת שם פרטי מחרוזת שם משפחה int age}

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

עובד נורמן = עובד חדש (1, "נורמן", "לואיס", 28) טוען נורמן. ToString () == "עובד (נורמן, לואיס, 28)" 

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

עובד snape = עובד חדש (2, "snape") טוען snape.toString () == "עובד (snape, null, 0)"

דומה ל @ToString, אנו יכולים להכריז על פרמטרים כגון לא כולל, כולל ו includeSuperProperties עם @TupleConstructor כדי לשנות את ההתנהגות של הבנאי המשויך שלה לפי הצורך.

4.3. @EqualsAndHashCode

אנחנו יכולים להשתמש @EqualsAndHashCode כדי ליצור את יישום ברירת המחדל של שווים ו hashCode שיטות בזמן הידור.

בואו נאמת את ההתנהגות של @EqualsAndHashCode על ידי הוספתו ל עוֹבֵד מעמד:

עובד normanCopy = עובד חדש (1, "נורמן", "לואיס", 28) טוען נורמן == normanCopy טוען norman.hashCode () == normanCopy.hashCode ()

4.4. @Canonical

@Canonical הוא שילוב של @ToString, @TupleConstructor, ו @EqualsAndHashCode ביאורים.

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

4.5. @ AutoClone

דרך מהירה ואמינה ליישום ניתנת לשיבוט הממשק הוא על ידי הוספת ה- @ AutoClone ביאור.

בואו נאמת את שיבוט שיטה לאחר הוספה @ AutoClone אל ה עוֹבֵד מעמד:

נסה {עובד נורמן = עובד חדש (1, "נורמן", "לואיס", 28) def normanCopy = norman.clone () טען norman == normanCopy} לתפוס (CloneNotSupportedException e) {e.printStackTrace ()}

4.6. רישום תמיכה עם @Log, @Commons, @ Log4j, @ Log4j2, ו @ Slf4j

כדי להוסיף תמיכה בכניסה לכל כיתת Groovy, כל מה שאנחנו צריכים זה להוסיף הערות הזמינות ב- groovy.util.logging חֲבִילָה.

בואו נאפשר את הרישום המסופק על ידי JDK על ידי הוספת ה- @עֵץ ביאור ל עוֹבֵד מעמד. לאחר מכן נוסיף את logEmp שיטה:

def logEmp () {log.info "עובד: $ lastName, $ firstName הוא בגיל $ age שנים"}

קורא ל logEmp שיטה על עוֹבֵד האובייקט יציג את יומני המסוף:

עובד שכיר = עובד חדש (1, "נורמן", "לואיס", 28) עובד.לוגמפ ()
מידע: עובד: לואיס, נורמן הוא בן 28

באופן דומה, ה @Commons ביאור זמין להוספת תמיכת רישום של Apache Commons. @ Log4j זמין עבור תמיכת רישום Apache Log4j 1.x ו- @ Log4j2 עבור Apache Log4j 2.x. לבסוף, השתמש @ Slf4j להוסיף חזית רישום פשוטה לתמיכה בג'אווה.

5. מסקנה

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

בדרך ראינו כמה תכונות מטא-תכנות בולטות הן לזמן ריצה והן לזמן הידור.

במקביל, בדקנו הערות שימושיות נוספות הזמינות ב- Groovy עבור קוד נקי ודינמי.

כרגיל, יישומי הקוד עבור מאמר זה זמינים ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found