10-152-312 - Object-Oriented Programming 2

3.5 Zoo Assignment

Implement the observer pattern with animal movement

  1. Create a new class library called Observers
  2. Create the IObserver interface as specified in the diagram above in the Observers package
  3. Create the ISubject interface as specified in the diagram above in the Observers package
  4. Have the IDrawable interface implement the ISubject interface
  5. Implement the ISubject interface in Animal
    1. Add a list of IObservers
    2. In the RegisterObserver() method, add the passed-in IObserver to the observer list
    3. In the UnregisterObserver() method, remove the passed-in IObserver from the observer list
    4. In the NotifyObservers() method, call the Update() method on each observer in the list
      1. You will need to create a temporary list and loop through that to avoid issues of looping through a list while objects are being added to it
    5. Call NotifyObservers() when the animal moves
  6. Comment out the requirement that Guest implement IDrawable (this will be fixed later)
  7. Implement the IObserver interface in DrawWindow
    1. In the DrawItem method, set the viewbox's Tag to the animal
    2. In the Remove() method, unregister the window from the passed-in ISubject and remove that subject's viewbox from the grid
    3. In the Update() method, remove the passed-in ISubject's viewbox from the drawableGrid and then re-draw it
      1. Put this code inside an Action delegate in the Dispatcher's Invoke method (like the code in the RepaintHandler)
  8. Remove the list of animals field and the parameter from the DrawWindow
    1. Also remove the AddDrawnItem method, which uses the now-deleted list
    2. Comment out the line(s) of code in the drawGuestButton click event handler that call AddDrawnItem to get the application to compile (this will be fixed later)
  9. When a new DrawWindow is shown:
    1. Add it to the dictionary of draw windows
    2. Get a list of animals of the specified animal type
    3. For each animal in the list, register the new window as an observer and notify the animal's observers
  10. Each time an animal is added to the zoo (through manual adding or birthing), register all cage windows of the corresponding animal type with the newly added animal
  11. Each time an animal is removed from the zoo, remove the animal from all cage windows of the corresponding animal type
  12. Add a window_Closed event handler to the DrawWindow
    1. In the handler, unregister the window from each item in the drawableGrid (items can be obtained from their viewbox)
  13. Remove the repaint timer and its event handler from DrawWindow, as the repainting is now handled by the observer pattern
  14. Run the application to ensure that animals still move and paint as they did before
    1. Animals will occasionally get stuck in the window after they have been removed
    2. Animals will occasionally flip the order in which they are drawn
    3. Drawing guests will not work at this point

Drawing guests using the observer pattern

  1. Uncomment the requirement that Guest implement IDrawable
  2. Implement the ISubject interface in Guest
    1. Add a list of IObservers
    2. In the RegisterObserver() method, add the passed-in IObserver to the observer list
    3. In the UnregisterObserver() method, remove the passed-in IObserver from the observer list
    4. In the NotifyObservers() method, call the Update() method on each observer in the list
      1. You will need to create a temporary list and loop through that to avoid issues of looping through a list while objects are being added to it
  3. In the drawGuestButton click event handler, register with the guest each window that is associated with the specified animal type
  4. Once all observers have been registered, notify the guest's observers
  5. Run the application
    1. Choose a guest and an animal and click the draw guest button
    2. Guests should be drawn in the cage window associated with the animal type of the chosen animal

Fixing animals getting stuck after being removed

  1. Add the IsSuspended read-only property and Suspend method to the IMover interface as specified in the diagram above
  2. Implement the new IMover interface in Animal
    1. Disable the moveTimer in the Suspend method
    2. Return true if the moveTimer is not enabled and false if it is enabled in the IsSuspended property
  3. Suspend an animal when it is removed from the zoo
  4. Add a test to the DrawWindow's Update() method - only call the DrawItem() method if the animal is not suspended

Fixing the drawing order

  1. Add the zIndex parameter to the DrawItem() method as specified in the diagram above
  2. In the DrawItem() method, instead of adding the viewbox to the drawableGrid, insert it using the zIndex
  3. In the DrawAllItems() method:
    1. Create a list of Drawables and add each viewbox's drawable to the list
    2. Clear the drawableGrid
    3. Initialize a zIndex variable to 0
    4. Draw each item in the temporary list, incrementing the zIndex variable each time
  4. In the Dispatcher's Invoke() method inside the Update() method:
    1. Initialize a zIndex variable to 0
    2. Loop through the viewboxes to find the viewbox associated with the passed-in subject
    3. Once the viewbox is found, set the zIndex to the current loop count and remove the viewbox from the grid
    4. Pass in the zIndex variable to the existing call to the DrawItem() method

Writing the hover behavior

  1. Create the HoverProcess enumeration as specified in the diagram above
  2. Create the HoverBehavior as specified in the diagram above
  3. Write the hovering algorithm as follows:
    1. The hover behavior spans multiple Move method calls. The behavior uses its field to keep track of how many steps are left in the current process before switching to the next process. It is easiest to start this variable at the max value and decrement it each time the animal moves.
    2. Move in the same random diagonal direction at 4x the animal's normal move distance for a random number of times between 5 and 8, inclusive (zooming mode)
    3. Then, move in a different random diagonal direction between 7 and 10 times, inclusive (hovering mode)

Allowing animal cages to be shown only once

  1. In the MainWindow's drawWindows dictionary, switch the key and value types so that the key is of type Type and the value is of type DrawWindow
  2. Each time an animal is added to the zoo, replace the existing loop with this code:
  3. Add the same code to the drawGuestButton click event handler, but register the window with the guest instead of the animal
  4. Each time an animal is removed from the zoo, replace the existing loop with this code:
  5. In the showAnimalCageButton click event handler:
    1. Refactor the existing code inside the null check to a method called CreateCageWindow that takes a Type and a DrawWindow as parameters
    2. If the animal type is not null (existing test):
      1. Define a DrawWindow variable but do not initialize it
      2. Try to get the dictionary value (window) that matches the animal type key
      3. If the window is not null:
        1. If the window is visible, activate it
        2. Otherwise, remove the key from the dictionary and recreate the cage window
      4. Otherwise, recreate the cage window
  6. Run the application
    1. Open an animal cage window
    2. With the window still open, try to open another cage window for the same animal type - another window should not open
    3. Serializing will not work because the dictionary still references DrawWindows

Fixing serialization

  1. Add a private method to MainWindow called CloseDrawWindows
  2. In CloseDrawWindows, close each window in the drawWindows dictionary
  3. Call CloseDrawWindows and set the drawWindows dictionary to null before saving the zoo
  4. Run the application
    1. Add some animals and guests
    2. Open one or more cage windows
    3. Close the application with all cage windows closed and with some cage windows open
    4. Restart the application to ensure that the zoo was saved and was deserialized correctly

3.5 Zoo Assignment: Package Diagram

Create/revise the classes as indicated by the following UML package (class) diagram.

PNG image of 3.5 Zoo UML detailed package (class)

Notes

3.5 Zoo Assignment: Class Diagram

Create/modify the classes as specified in the following UML class diagram.

PNG image of 3.5 Zoo UML class diagram

Grading and Submission

  1. Build/compile your program
  2. Debug/test your program against the following rubric:
  3. PNG image of 3.5 Zoo rubric
  4. Make your code StyleCop-compliant
  5. Close your Visual Studio solution
  6. Compress your Visual Studio solution to a zip file
  7. Submit the zip file via Blackboard