java programming
Name CS117 Lab 03 – Page 1
Lab 03: Refactoring Room
Assigned: Tuesday, January 30, 2018 Due: Sunday, February 4, 2018 at 6:00am
1 Overview
In this lab we are going to continue refactoring the code that was provided for your game to improve its design and implementation. “Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.”1 It is the process of reorganizing code to provide a better design while maintaining equivalence. When we refactor code, we want the quality of the code to improve while keeping the functionality of the code exactly the same.
1.1 Cohesion
A well-designed class has all of the code that it needs, and no more code. It should represent one clearly- defined kind of thing. Every method should have one specific purpose, and it should be obvious what that purpose is. The same code should not be repeated multiple places. Classes with these properties are cohesive. We already improved the cohesiveness of the Game class in the first lab when we moved duplicate code into the new printLocationInformation method.
1.2 Coupling
A well-designed class can be used correctly without knowledge of the details of how it works, so that when those details change it will not be necessary to change the code that uses it. When this is true, classes are loosely coupled. When a class depends highly on the messy details of another, they are highly coupled. Currently, the Room class is tightly coupled with several other classes. We are going to fix the design of the Room class today to fix this.
2 Assignment
2.1 Resolving Issues
If you have any outstanding issues from prior labs, you should fix those before doing anything else. Remember to use one commit per issue, and to include “Fixes #4” (or whatever number it is) in your commit message.
2.2 Fixing Some Bad Style
We have learned that unless there is a very good reason to do otherwise, fields should always be private. Keeping fields private decreases the coupling between classes because it allows things to change behind the scenes without having to change multiple classes. If you look at the Room class, you will find that it contains public fields. We are going to fix this now. Start by changing each of them to private.
But now, when you try to compile the code, you will find that there are lots of compiler errors because of places outside the Room class that had been using those public fields. We still need to have ways for other code to get information about Room objects, so we need to write some accessor and mutator methods in it.
1Martin Fowler in Refactoring: Improving the Design of Existing Code, 1999.
Name CS117 Lab 03 – Page 2
You will then need to update every class that uses those fields directly to use your newly written accessor and mutator methods instead. (Hint: The easiest way to do this is to let the compiler tell you about those places.) Look for opportunities to simplify the code as you do this. Again, make sure that you test your code to make sure that it still works, then commit and push your changes.
2.3 Improving Cohesion
Writing cohesive code means that the Game class really shouldn’t know all of the possible exits that a Room can have or really know the details of what it means to write out the details of a room. It would be better for the Room class to handle this. The perfect way to do this is to create a toString method in the Room class:
1 /∗ ∗ 2 ∗ R e t u r n s a s t r i n g d e s c r i p t i o n i n c l u d i n g a l l t h e d e t a i l s o f a Room . 3 ∗ F o r e x a m p l e , 4 ∗ O u t s i d e : 5 ∗ You a r e o u t s i d e i n t h e c e n t e r o f t h e King ’ s C o l l e g e campus . 6 ∗ E x i t s : n o r t h e a s t s o u t h w e s t 7 ∗ 8 ∗ @ r e t u r n A s t r i n g r e p r e s e n t i n g a l l t h e d e t a i l s o f a Room . 9 ∗/
10 public String toString ()
As you can see, this method should print first the room’s name, then its description, then a list of all the directions out of the room (those that are not null).
Remember that we want to keep the output isolated in a single class so we don’t really want this method to print the exit string directly – only to return it. Modify the Game class to use the toString method instead of relying on knowledge of all the possible exits a Room can have. Be sure that you test to make sure that your modifications didn’t change the behavior of the application. Then commit and push your changes.
2.4 Adding Support for Multiple Directions
Currently, a player can only move in four directions. What if we wanted to add a new direction of movement to our game? How many places in the code would need to be modified in order to add a new direction (e.g., up) or down)? Fortunately, the work we have done to clean up the interface to the Room class means that it is now easier to change the way exits are stored in the Room class without any need to worry about breaking anything in the Game class.
We would like to add support in our game for movement in any arbitrary direction, rather then try to anticipate all of the directions our game may need. We will refactor the Room class to use a HashMap to store exits. The HashMap will map a named direction (like "north" or "east") to the Door that lies in that direction. We will do this now.
1. Replace the individual exit fields of the Room class with a HashMap. The HashMap should map a direction string to the Door that is located in the specified direction. Be sure to completely delete the individual fields for each of the directions.
2. Since we no longer have individual fields for each exit, replace the mutator methods for old fields we just added with a new setExit method that can handle an exit in any direction. This method only needs to put the exit information into the HashMap. It should have the following signature:
Name CS117 Lab 03 – Page 3
1 /∗ ∗ 2 ∗ D e f i n e s an e x i t f r o m t h i s room . 3 ∗ 4 ∗ @param d i r e c t i o n The d i r e c t i o n o f t h e e x i t . 5 ∗ @param n e i g h b o r The d o o r i n t h e g i v e n d i r e c t i o n . 6 ∗/ 7 public void setExit(String direction , Door neighbor)
3. Similarly, we can replace the accessor methods for the old fields we added earlier with a new getExit method that can return the exit that exists in any direction. This method need only get the exit information from the HashMap. It should have the following signature:
1 /∗ ∗ 2 ∗ G e t s a d o o r i n a s p e c i f i e d d i r e c t i o n i f i t e x i s t s . 3 ∗ 4 ∗ @ r e t u r n The d o o r i n t h e s p e c i f i e d d i r e c t i o n o r n u l l i f i t d o e s n o t
e x i s t . 5 ∗/ 6 public Door getExit(String direction)
4. Modify the rest of the Room class so that it properly uses the HashMap. HINT: The toString() method can iterate over the keys of the HashMap.
5. Modify the goRoom method in the Game class to use your newly written getExit() method. HINT: Look for an opportunity to greatly simplify this code.
6. Finally, we need to modify the World class. Notice that the World class has methods for each of the directions. We should be able to simplify this by replacing all of the direction specific methods for creating doors with a single method similar what we did in the Room class:
1 /∗ ∗ 2 ∗ H e l p e r method f o r c r e a t i n g d o o r s b e t w e e n r o o m s . 3 ∗ 4 ∗ @param f r o m The room w h e r e t h e d o o r o r i g i n a t e s . 5 ∗ @param d i r e c t i o n The d i r e c t i o n o f t h e d o o r i n t h e f r o m room . 6 ∗ @param t o The room w h e r e t h e d o o r g o e s . 7 ∗/ 8 private void createDoor(Room from , String direction , Room to)
Congratulations, you have modified your game in such a way that we can create a multi-dimensional world in which our player can move in any direction. Be sure to test to make sure that your modifications didn’t change the behavior of the application and then commit and push your changes.
2.5 Introducing Checkstyle
We have talked a lot about why it is beneficial to use good style when programming. Sometimes, however, we are so focused at the task that we are trying to accomplish that we forget to following some of our coding
Name CS117 Lab 03 – Page 4
standards. The result of this is that we have code that is harder to understand. In order to help us develop good habits, we will use a tool called Checkstyle.
Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard. It automates a lot of the process of checking Java code to spare humans of this boring (but important) task. This makes it ideal for projects that want to enforce a coding standard like this project. You can run Checkstyle on your project to make sure that it follows the standards we have been teaching you this year.
The first thing we want to do is check that we are using the correct style file. You can double check the style file that BlueJ is using by going to the “Tools” ... “Preferences” menu and selecting the “Extensions” tab. At the top of this tab are two text fields for where Checkstyle will look for its configuration. Be sure that both of them point to http://www.kings-cs.com/kings-cs/java/kings-cs-lower.xml.
Now run Checkstyle from the “Tools” menu. This should open a window that lists any problems that were detected in your program. If there are any problems, you should fix them. You should do this at minimum before everytime that you complete an assignment in this course (and all future programming courses).
If you needed to make any changes to fix Checkstyle problems, run your program again to make sure that it still works, and then commit and push your changes.
If you downloaded BlueJ to your own computer, it probably does not have Checkstyle installed, because it is an extension. You should follow the instructions at http://bluejcheckstyle.sourceforge.net/ to install activate Checkstyle for your copy of BlueJ, because you should be running it before every commit and push that you do for this project (and homework assignments too)! If you need help with this, ask!
2.6 Design Document
That is all of the code that you need to write for today. If you have extra time, work on / talk to me about your design document.
3 Finishing
When you are finished, you will need to send me information about which commit is the final one for this assignment. To do so, refresh the github.com page for your repository one more time. Then find the section labeled “Latest commit” followed by a strange sequence of seven numbers and letters, then the date. If you click on the numbers and letters, you will go to a page showing the changes made in your most recent commit.
Copy the URL of that webpage and paste it into the Moodle submission box. (I can show you how to do all of this if you are unsure.) Make sure that you click the “Submit Assignment” button in Moodle.
To avoid any confusion, I strongly recommend that you delete the repository from your local computer and re-clone it next time you are ready to work on it.