Design and Implementation

In this chapter we extend the tiled map case study by considering model encapsulation and additional setArea(...) behaviour.



Encapsulating the model.

What we have looked at up to now is really only the state of the model. That is, how its structure and values are represented; in this case by a 2D array and an enum type respectively. We have also introduced an initial encapsulation through the TiledMap3 class developped in the previous chapter. It is now time to focus on the design of the model by reviewing again the requirements identified in the case study introduction.

These requirements stated that a client application should be able to use the model to ...

  1. create a map of any size;
  2. retrieve the size of the map;
  3. model different terrain contexts;
  4. initialize the map to some specific terrain type from the context;
  5. get and set the terrain type for a particular (x,y) tile;
  6. render the map to some output device;
  7. allow a border to be set to a terrain type;
  8. set subareas of the map to a specific terrain type, perhaps randomly;

Reviewing these requirements we can identify that we have met items A to F although we should now review our solution and consider any refinements that can make our solution more robust, flexible and maintainable.

Although we have implemented requirement F, this is only for the console device. This requirement will be further explored in the chapter on rendering with a strategy pattern for other output devices.

In relation to requirement C, the terrain context is application dependant in terms of its values, what we require to do here is design a model that is as flexible as possible in terms of including different terrain contexts. All we can know at this stage is that we require an enum called TerrainType. Therefore code the enum declaration in a seperate .java file that can be replaced to reflect the terrain context requirements of an actual scenario.

The behaviour of the tiled map model should therefore only refer to TerrainType and not require to know anything about its values.

  1. Create a seperate 'TerrainType.java' file and define the TerrainType enumeration to represent the terrain context for outdoor landscape with grass, tree, bush, earth, rock, river, water, fence, cliff and ravine tile types.
    Remember to adopt good programming practice in terms of commenting, naming, layout, etc.

The tiled map class can be designed by first identifying the behaviour without having to worry about its implementation (i.e. define WHAT we can do without defining HOW we are going to do it).
this is accomplished by first defining an interface that defines public methods with no iplementation.

  1. Create the file 'ITiledMap.java' and define the ITiledMap interface for the exposed behaviour of the tiled map model.
    At this stage only include the behaviour we have met already for requirements A to F.
  2. Add the setBorder(...) method to the interface that will allow us to meet requirement G; that is, the ability to define a border on the map set to a supplied terrain type.
    Allow optionally to define the width of this border.

So we now have the TerrainType enum and ITiledMap interface components that both design & define a representation for the different tiles available on our map together with what we can do with a map. From this design phase, we now require to move on to implementation; i.e. programming how this design works.

The state (2D array) should now be encapsulated into a concrete class together with the implementation of the behaviour defined by the interface. This concrete class will also require constructor method(s) to be defined since they are not part of an interface.

  1. Create the 'TiledMap.java' file and define the TiledMap class that implements the ITiledMap interface.
    1. Define the 2D array as a private field.
    2. Include overloaded constructors for defining
      • a tiled map of a defined size (leave the array elements initialised as null) and
      • a tiled map of a defined size with the terrain type to be used to initialise it.
    3. Implement the interface methods as before.
    4. Remember you now have the additional setBorder() behaviour to implement; the width parameter for this method should ve validated and appropriate response made such as having the method return a boolean indicating success or failure.
  2. In a seperate file construct a main application class to test and exercise the model.
    You ight do this by drawing out some outdoor landscape map on paper and writing appropriate code that will represent this map using the model.
  3. Compile, execute and review the application.

These activiteies illustrate that when designing and implementing �



Adding more behaviour.

Let us now consider meeting requirement H which requires the model to expose behaviour to allow a specific terrain type to be set in some rectangular subarea within the map, perhaps randomly. The random generation will be considered later, let us first consider setting an area to a single terrain type value.

this behaviour will be exposed through the setArea(...) method taking the subarea definition and terrain type as parameters.

  1. Consider how to define the subarea; this might be in terms of ...
    • coordinates of one corner with the width and height of the subarea;
    • coordinates of the centre of the subarea with the width and height of the subarea;
    • coordinates of diagonally opposite corners;
    • or some other definition.
    Decide on one of these to use as the mechanism for subarea definition.
  2. Consider what happens if an invalid subarea definition (i.e. partly or wholly outside the map) is supplied as parameter to the method. Possible approaches to this are to ...
    • return without setting any part of the subarea;
    • set the part of the subarea (if any) that is within the map, ignoring the rest.
    Also consider what indication the method should provide to the client code that an invalid subarea has been supplied. this could be accomplished by ...
    • providing no indication;
    • returning a bool;
    • throwing an exception.
    Consider the effect of these approaches on what the client application can and cannot do and hence decide on the approach to take in your model.
  3. Amend the ITiledMap interface to include the setArea(...) method as you have identified above.
  4. Amend the tiledMap class to provide an implementation of the setArea(...) method.
  5. Amend your exerciser application to include tests for the correct operation of the setArea(...) method, including its handling of an invalid subarea definition.

Requirement H also indicated that the model should have the ability to randomly generate a subarea of map.

This will require our code to create random numbers; in Java this is handled by the java.util.Random class. To review how to generate random numbers in Java you can review the following references:

the term "randomly generate" is ambiguous; it might apply to

So to introduce random area setting behaviour we will first have to decide on which of the above we will incorporate into our model.

  1. Design appropriate subarea random generation behaviour by adding methods (or one overloaded method) to the interface.
  2. Amend the concrete class to implement the revised interface.
  3. Add appropriate exercise code in your main application.
  4. As usual, compile, execute and review your application and the tiled map model.

Reviewing this section it is quite surprising that such a simple requirement as setting a subarea of the map could lead to so many design decisions needing to be made. Never under-estimate the complexity of what are apparently simple problem areas!