הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
2012 נושאים בהנדסת תוכנה –סמסטר אביב
Refactoring & Design By Contract – 5 עבודה מספר
24/6/2012 :תאריך הגשה
Refactoring : חלק א
(15%) 1 שאלה
. נמקו ותנו דוגמאCode restructuring לRefactoring מה ההבדל בין
.א
(עיינו במצגות האורחextract computation - לextract method הסבירו מה הבדל בין
.)העוסקות בנושא
.extract method זהה לextract computation הגדירו באיזה מקרה
.ב
Fowler עיינו בדוגמת חנות הוידאו של.ג
על מנת להפטר מהמשתניםreplace temp with query בצעד השישי פאולר מבצע
: להלן המוטיבציה."הזמניים האוגרים את סה"כ החיוב וסה"כ נקודות "השוכר המתמיד
Removing Temps
As I suggested before, temporary variables can be a problem. They are useful only within
their own routine, and thus they encourage long, complex routines. In this case we have
two temporary variables, both of which are being used to get a total from the rentals
attached to the customer. Both the ASCII and HTML versions require these totals. I like
to use Replace Temp with Query to replace totalAmount and frequentRentalPoints
with query methods. Queries are accessible to any method in the class and thus encourage
a cleaner design without long, complex methods:
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
כפי שמתוארת בספר שלReplace Temp with Query עקבו אחרי המכניקה של.a
:פאולר
Replace Temp with Query - Mechanics
Here is the simple case:
Look for a temporary variable that is assigned to once.
? If a temp is set more than once consider Split Temporary Variable.
Declare the temp as final.
Compile.
? This will ensure that the temp is only assigned to once.
Extract the right-hand side of the assignment into a method.
? Initially mark the method as private. You may find more use for it later, but you
can easily relax the protection later.
? Ensure the extracted method is free of side effects, that is, it does not modify any
object. If it is not free of side effects, use Separate Query from Modifier.
Compile and test.
Use inline temp on the temp.
Temps often are used to store summary information in loops. The entire loop can be
extracted into a method; this removes several lines of noisy code. Sometimes a loop may
be used to sum up multiple values, as in the example on page 26. In this case, duplicate
the loop for each temp so that you can replace each temp with a query. The loop should
be very simple, so there is little danger in duplicating the code.
זה במדויק כדי להחליף אתrefactoring מה הבעיה במכניקה המתוארת אם ברצוננו לבצע
? כפי שעשה פאולר, במתודה המחשבת אותוtotalAmount המשתנה
ניתן היה לבצע את השכתוב שבצע פאולר (עיינו בהרצאתrefactoring באמצעות אלו.b
.)אורח בנושא
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
(10%) 2 שאלה
:ענו על השאלות הבאות
.? נמקו ותנו דוגמא מקוריתstate איזה "ריח רע" יכול להצביע על הצורך בתבנית עיצוב.א
. הבאrefactoring מופיע הJoshua Kerievsky בספרו של
Replace State-Altering Conditionals with State
The conditional expressions that control an object's state transitions are complex.
↓
Replace the conditionals with State classes that handle specific states and transitions
between them.
.ב
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
Mechanics
1. The context class is a class that contains the original state field, a field that gets
assigned to or compared against a family of constants during state transitions.
Apply Replace Type Code with Class (286) on the original state field such that its
type becomes a class. We'll call that new class the state superclass.
The context class is known as State: Context and the state superclass as State:
State in Design Patterns [DP].
o
Compile.
2. Each constant in the state superclass now refers to an instance of the state
superclass. Apply Extract Subclass [F] to produce one subclass (known as State:
ConcreteState [DP]) per constant, then update the constants in the state superclass
so that each refers to the correct subclass instance of the state superclass. Finally,
declare the state superclass to be abstract.
o Compile.
3. Find a context class method that changes the value of the original state field based
on state transition logic. Copy this method to the state superclass, making the
simplest changes possible to make the new method work. (A common, simple
change is to pass the context class to the method in order to have code call
methods on the context class.) Finally, replace the body of the context class
method with a delegation call to the new method.
o Compile and test.
Repeat this step for every context class method that changes the value of the
original state field based on state transition logic.
4. Choose a state that the context class can enter, and identify which state superclass
methods make this state transition to other states. Copy the identified method(s),
if any, to the subclass associated with the chosen state and remove all unrelated
logic.
Unrelated logic usually includes verifications of a current state or logic that
transitions to unrelated states.
o
Compile and test.
Repeat for all states the context class can enter.
5. Delete the bodies of each of the methods copied to the state superclass during step
3 to produce an empty implementation for each method.
o Compile and test.
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
השוו בין refactoringזה לבין זה שנלמד בכתה על פי ספרו של פאולר
Replace Type code with State/Strategy
מצאו לפחות שתי נקודות דמיון ושתי נקודות שוני ביניהם.
הציגו את ההשוואה בטבלה – תנו שם לכל קריטריון והסבירו את הדמיון או את השוני
שאלה (15%) 3
נתון קטע הקוד הבא:
{ )public double m(int z
;double y = m1() / z + 209
)while(z % 2 == 0
;z = z / 2
;double w = y + 187.27
5
;)return m2(w,y,z
6
7
}
א.
1
2
3
4
מפתח המערכת מעוניין לבצע replace temp with queryעל משתנה . y
בצעו את ה .refactoringבכל ביצוע refactoringיש להסביר את קיום תנאי
ההפעלה ולהצדיק את שלבי השכתוב.
ב.
האם הקוד המקורי שקול לזה שהתקבל בסעיף הקודם ? נמקו.
ג.
נסחו תנאי מקדים שיש להוסיף ל replace temp with queryשישקף את
תשובתך לסעיף הקודם.
שאלה (20%) 4
עיינו בקוד הבא :
{ public abstract class Trip
;)public abstract void tripPlan(int length
;)(public abstract void doComingTransport
;)public abstract void doCityTrack(int day
;)public abstract void doNatureTrack(int day
;)(public abstract void doReturningTransport
}
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
public class PackageSummer extends Trip {
public void tripPlan(int length) {
doComingTransport();
doCityTrack(1);
for (int i=2; i<=length-1; i++)
doNatureTrack(i);
doCityTrack(length);
doReturningTransport();
}
public void doComingTransport() {
System.out.println("The turists are comming by boat ...");
}
public void doReturningTransport() {
System.out.println("The turists are going home by boat ...");
}
public void doCityTrack(int day) {
System.out.printf("The turists are doing the city track of day
%d\n",day);
}
public void doNatureTrack(int day) {
System.out.printf("The turists are doing the nature track of day
%d\n",day);
}
}
public class PackageWinter extends Trip {
public void tripPlan(int trip_length){
doComingTransport();
for (int i=1; i<trip_length; i++)
if (isRainyDay(i)==0)
doCityTrack(i);
else
doNatureTrack(i);
doReturningTransport();
}
public void doComingTransport() {
System.out.println("The turists are comming by air ...");
}
public void doReturningTransport() {
System.out.println("The turists are going home by air ...");
}
public void doCityTrack(int day) {
System.out.printf("The turists are doing the city track of day
%d\n",day);
}
public void doNatureTrack(int day) {
System.out.printf("The turists are doing the nature track of day
%d\n",day);
}
public int isRainyDay(int day){
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
return 0;
}
}
למחלקה אחרת לפיtripPlan מפתח המערכת הגיע למסקנה שיש להעביר את השיטה
.א
. הסבירו מדוע. אולם השכתוב אינו אפשרי.Move Method
Form Template Method . : מתוך הקטלוג של פאולרrefactoring להלן
.ב
Form Template Method
You have two methods in subclasses that perform similar steps in the same order, yet the
steps are different.
Get the steps into methods with the same signature, so that the original methods become
the same. Then you can pull them up.
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
Motivation
Inheritance is a powerful tool for eliminating duplicate behavior. Whenever we see two
similar methods in a subclass, we want to bring them together in a superclass. But what if
they are not exactly the same? What do we do then? We still need to eliminate all the
duplication we can but keep the essential differences.
A common case is two methods that seem to carry out broadly similar steps in the same
sequence, but the steps are not the same. In this case we can move the sequence to the
superclass and allow polymorphism to play its role in ensuring the different steps do their
things differently. This kind of method is called a template method [Gang of Four].
Mechanics
Decompose the methods so that all the extracted methods are either identical or
completely different.
Use Pull Up Method to pull the identical methods into the superclass.
For the different methods use Rename Method so the signatures for all the
methods at each step are the same.
This makes the original methods the same in that they all issue the same set of
method calls, but the subclasses handle the calls differently.
Compile and test after each signature change.
Use Pull Up Method on one of the original methods. Define the signatures of the
different methods as abstract methods on the superclass.
Compile and test.
Remove the other methods, compile, and test after each removal.
זה נוכל להפעיל אתrefactoring הסבירו כיצד באמצעות הפעלה מוקדמת של
. על השיטה המבוקשתMove Method
שכתבו את הקוד צעד אחר.' לפי ההסבר שנתתם בסעיף בrefactoring -הפעילו את ה
.ג
.) ולוו כל צעד בהסבר קצר (שורה אחתrefactoring צעד לפי הנחיות ה
– לו ביצענו את ההעברה איזה ריח רע היהmove method כעת משניתן להפעיל את
.ד
.נוצר ? הסבירו מדוע
אוניברסיטת בן גוריון
הפקולטה למדעי הטבע
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
חלק ב Design By Contract
שאלה (12%) 5
בשאלה זאת נעסוק במשחק הלוח מונופול ( )Monopolyכאשר נתמקד בהזזת השחקן על לוח
המשחק.
בלוח המשחק יש 40תאים (נסמנם ב )0-39כאשר השחקנים מתחילים בתא 0ובכל תור
מתקדמים כמות מסוימת של תאים קדימה .כאשר השחקן מגיע לתא האחרון ( )39ועליו
להתקדם הוא יתחיל שוב מתא .0
לדוגמא :אם השחקן בתא 38ועליו לזוז 5תאים קדימה הוא יעבור לתא .3
ניתן לקרוא עוד על המשחק ב Wikipedia
לפניכם חוזה חלקי של המחלקה Monopolyהכולל תנאי קדם תנאי קדם )(pre condition
ותנאי בתר ).(post condition
Class Monopoly
getLocation() : int
Purpose: return current player's location on the board
getMoney() : int
Purpose: return current player's money
)moveForward(int steps
Purpose: Move the current player location on the board "steps" steps.
)Require: (steps>=0 AND steps <= 12
))(Ensure: ((getLocation()@pre + steps) mod 40) == getLocation
בחברת הפיתוח הוחלט להרחיב את המשחק על ידי הורשה .כל תת מחלקה משכתבת את
השיטה .moveForward
להלן הרחבות אפשריות:
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
א .הרחבה :יש למנוע משחקנים תזוזה של בדיוק 5תאים:
)moveForward(int steps
)Require else: (steps!=5
הסבירו במילים את משמעות התנאי הקובע בתת המחלקה.
האם החוזה בתת המחלקה משרת את ההרחבה הנדרשת? אם כן ,הסבירו .אם לא,
נמקו ותנו דוגמא.
ב .הרחבה :שחקן יכול לבצע תזוזה לכיוון הנגדי:
)moveForward(int steps
)Require else: (steps>= -12 AND steps <= 12
הסבירו במילים את משמעות התנאי הקובע בתת המחלקה.
האם החוזה בתת המחלקה משרת את ההרחבה הנדרשת? אם כן ,הסבירו .אם לא,
נמקו ותנו דוגמא.
ג .הרחבה :יש להוסיף משבצת חדשה (מס' )40על הלוח על מנת שיהיו 41משבצות:
)moveForward(int steps
))(Ensure then: ((getLocation()@pre + steps) mod 41) == getLocation
האם החוזה המשוכתב בתת המחלקה הוא משמעותי? אם כן -נמקו ונסחו את תנאי
הבתר הקובע אם לא -נמקו ותנו דוגמא נגדית.
ד .הרחבה :כאשר השחקן מבצע הקפה של הלוח ,יקבל : ₪ 200
)moveForward(int steps
Ensure then: (getLocation()>=0 AND getLocation() – steps <0) implies
))((getMoney()@pre + 200 == getMoney
האם החוזה המשוכתב בתת המחלקה הוא משמעותי? אם כן -נמקו ונסחו את תנאי
הבתר הקובע אם לא -נמקו ותנו דוגמא נגדית.
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
שאלה (28%) 6
מבוך מוגדר כלוח של nxmחדרים ( )m>1, n>1כאשר בכל חדר יש (לכל היותר) 4קירות
בכל אחד מהכיוונים (ימינה,שמאלה,למעלה,למטה) .בחלק מהקירות ממוקמות דלתות אשר
חלקן נעולות.
בתחילת המשחק השחקן נמצא בחדר שמיקומו ( (1,1וברשותו מספר מפתחות בעזרתם
ניתן לפתוח דלתות נעולות ,ומספר צעדים שאותם הוא יכול לבצע .כמו כן בעת אתחול
המשחק מועברת רשימת הקירות הפנימיים.
השחקן יכול להשתמש בצעד על ידי מעבר לחדר סמוך .מעבר דרך דלת אפשרי רק כאשר
הדלת אינה נעולה .השחקן יכול להשתמש במפתח על מנת לפתוח דלת פנימית נעולה.
המשחק נגמר בניצחון כאשר השחקן מגיע לחדר שמיקומו ) (m,nובידיו לפחות מפתח אחד.
המשחק נגמר בהפסד כאשר לשחקן נגמרו המפתחות או נגמרו הצעדים.
המחלקה Mazeמספקת את השירותים ) (featuresהבאים:
1. initialize(int n, int m, Collection<Wall> walls, int keys, int moves): Maze
Purpose: Creates a new Maze object, with nxm rooms and walls.
2. reduceMoves (): int
Purpose: reduces the amount of moves by one and returns the updated
amount.
3. isGameOver(): Boolean
Purpose: returns true if game is over.
4. getX (): int
Purpose: returns the player's X location.
5. getY (): int
Purpose: returns the player's Y location.
)6. setLocation(int x, int y
Purpose: sets the player's location.
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
7. getKeys(): int
Purpose: returns the amount of player's keys.
8. reduceKeys()
Purpose: reduces the amount of player's keys by one.
// Methods for left Wall
9. getLeftWall() : Wall
Purpose: Returns the wall on the left.
10. moveLeft(): Boolean
Purpose: if possible to move to the room on the left, move and return true.
Otherwise return false.
11. unlockLeftDoor (): Boolean
Purpose: if possible to unlock the left door, unlock it and return true.
Otherwise return false.
// Methods for the right up and down walls (getWall, unlockDoor, move)
…
:( הבאיםfeatures) מספקת את השירותיםWall המחלקה
1. initialize(int r1x, int r1y, int r2x, int r2y, Boolean hasDoor, Boolean
lockedDoor):Wall
Purpose: Creates a new Wall Object, between room r1 to room r2.
2. getR1x(): int
Purpose: returns the X location of room r1.
3. getR1y(): int
Purpose: returns the Y location of room r1.
4. getR2x(): int
Purpose: returns the X location of room r2.
5. getR2y(): int
Purpose: returns the Y location of room r2.
הפקולטה למדעי הטבע
אוניברסיטת בן גוריון
המחלקה למדעי המחשב – התכנית להנדסת תוכנה
6. hasDoor() : Boolean
Purpose: returns true if the wall has a door
7. isLockedDoor(): Boolean
Purpose: returns true if the door is locked
)(8. unlockDoor
Purpose: unlocks the door
פיתוח חוזה עבור המחלקה :Maze
א .הבחינו בין queriesל commands-בתיאור ההתחלתי של השירותים.
ב .פתחו חוזה למחלקה Mazeלפי הכללים לפיתוח חוזה שנלמדו בכיתה.
ניתן להוסיף פעולות נחוצות – אולם יש להצדיק כל הוספה.
אין צורך לפתח את הפעולות getWall, move, unlockDoorעבור ארבעת הכיוונים.
מספיק לפתח עבור כיוון שמאל.
במנשק ( )interfaceשהתקבל הבחינו בין סוגי הפעולות השונות:
basic query / derived query / command
© Copyright 2026 Paperzz