Programming practice and enumerations.

In all the Java code you write from now on you are expected to adhere to the elements of good programming practice identified in lectures, and illustrated in any example Java source code you are provided with.

This chapter covers good programming practice and enumerations.
these topics were outlined in the good practice and enumerations presentation (opens in new window) that you should review.

Good Programming Practice.

  1. Download the eg3.java source code file.
  2. Compile, execute & review this program and hence answer the questions that follow.
  3. Identify the different items documented in the header commentary and explain why these are relevant, and indeed important, to a developer.
  4. What naming conventions are used in this program?
  5. This file is identical in function to the eg2.java file used in the previous chapter; however it is refactored to adhere to good programming practice.
    Compare and contrast these two programs:
    1. What are the differences?
    2. Which is best?
    3. Justify your choice.
  6. Literal constants are explicit values in your code such as 123 (int); 6.5430 (double); "hello" (String).
    1. Why is it good practice to minimise the use of literal constants in your code?
    2. Identify the literal constants used in App2_0.
    3. How is their use avoided in App3_0?
    4. ... and so why is the approach of App3_0 so much better?
  7. In "App3_0.java" the final keyword is used liberally.
    1. Review the wikipedia article on the use of final in Java.
    2. What is the significance of the App3_0 and TiledMap3_0 classes being 'final'?
    3. Why are the methods not defined as 'final'?
    4. Explain the properties of the mMap field.
    5. Identify variables that are defined as 'final' and those that are not; explain why they are defined differently.

Enumerations.

One aspect of good programming practice is the appropriate use of enumerations and so we shall review these here and apply to the tiled map case study.

In the previous tiled map model we used an array of boolean values to represent the tiles. this is fine when we are in a terrain context that only requires to discriminate between passable and impassable tiles. What if we require to use a more complex terrain context with, for example, grass, hedge, water, fence and soil tiles?

An obvious solution is to use a 2D array of integers rather than booleans, with different integer values representing different terrain types. For example, 0=grass, 1=hedge, 2=water, 3=fence, 4=soil.

However this approach is not very readable, robust or maintainable.

  1. Why is the use of an int[][] array not readable, robust or maintainable?
    (Describe at least 1 reason for each)

A preferred representation of multiple terrain types is an enum, with one value for each different kind of terrain type. This also looks forward to a more featured terrain type representation where the enum is used to define associated attributes such as rendering character/colour and other features.

  1. Define an appropriate enum declaration called TerrainType for the terrain context identified above.
  2. Define a tiledMap3 class that models the map as a 2D array of the Terraintype enumeration.
    this can be a reworking of the behaviour of the TiledMap3_0 class defined in App3_0.java.
    Note that in this implementation the get and set methods for the tile position both do no validation checking on the (x,y) coordinate; therefore if it is invalid an array out of bound exception will be thrown. An alternative approach would be to explicitly check for validity and take some other action such as throwing an application specific exception.
  3. Write a console program to exercise your model and allow you to answer the following questions:
    1. What values will the array elements be set to by default?
    2. How can you fill the map with a specific tile type?
    3. What is displayed on the console for a map tile value?
    4. How can you set a tile to a different terrain type?
      for example, to create a map for the lawn with hedge boundary met previously; add a diagonal strip of 2 tile widths of water from (0,0) to (10,10).
  4. Modify the TiledMap3 class to expose a render() method that will display the map on the console.
    • Obviously a nested for loop is used for this but in what order do we print out the map?
      Remember we interpret the map in terms of x,y coordinates while it is stored as rows/columns and we wil need to print the map from the topmost row down.
    • If you simply print out the value of the array elements then this will print out the name of the enum value and hence will take up multiple and variable characters on the screen. You can use a switch statement in your rendering method to test the tile type value and print an appropriate single character instead of the enum value name.
         switch (mMap[x][y]) {
         case TerrainType.GRASS: ... ... ...
         ... ... ...
         }
      

  5. Amend your exercise program to call the render() method and check that the output matches your expectations.

Abstracting the model.

While the use of the switch statement in printing out a tile as a character works effectively it results in the tiledMap3 class being what we call strongly coupled to the Terraintype enumeration. That is, we explicitly code in specific enum balues in the case elements.

This means that our TiledMap3 class is now specific to only one particular terrain context; for example, what would we have to change if we were now to map an computer room that had floor, table, chair and computer terrain types?

there is a more elegant solution to our problem in which we can do away with the switch statement and leave the TiledMap3 class entirely de-coupled of the actual Terraintype values (although obviously it still needs the type). We do this by amending the Terraintype definition to expose an attribute that will provide a single character representation for each value. This character can then be used in the render() method to print a more readable version of a map.

We will code this in the following steps and you can follow the details by reviewing again the Oracle enum types tutorial.

  1. Make amendments to the TerrainType enum type as follows:
    • Add a private char field.
    • Add a private constructor TerrainType (char aChar) to initialize the field to the parameter.
    • amend the definition of the actual enum values to pass an appropriate character to the constructor.
    • Add a public asChar() method to return the field.
  2. Amend the rende()r method of the tiledMap3 class by removing the switch statement and instead retrieving the single character to print by calling the asChar() property of the enum balue.
    Your exercising program should not require any changes since it only calls the render() method of the TiledMap3 object.
  3. Compile, execute and review these amendments; the map should now be rendered on the console as single characters.
  4. In preparation for future work, amend the Terraintype definition to expose a boolean isPassable() attribute for each enum value that indicates whether or not the tile value represents a passable area of terrain in the map.
    this is accomplished through following the same stepps as for the asChar() attribute above.
    The terrain tile values will now require 2 values in their constructor call; a character representation and a true/false passable indicator.
       public enum TerrainType
       {
          GRASS ('.', true),
          ...;
    
          ... ... ...
       } // end Terraintype enumeration.
    

  5. ... and finally, reflect on these changes that you have made and how they afect the readability, robustness and maintainability of your application. For example, you might consider:
    1. how de-coupled the client, TerrainType and tiledMap3 components are from one another?
    2. can you use these components (without changes) in another application?
    3. what do you have to change if you wish to map a different outdoor landscape?
    4. what do you have to change if you wish to use different characters for the terrain types?
    5. what requires to be changed if you are to map a different terrain context, e.g. a computer room layout or city map?

Remember that from now on you are expected to adhere to the elements of good programming practice identified in lectures and illustrated in any example Java source code you are provided with.