0

I am making a game of Monopoly. I call a method in my Board class which returns the current players square object! E.g Old Kent Road. Euston, Chance , Free parking. I use polymorphism to decide upon the logic of what should happen depending of the state of the square! E.g I’ll have a property class where a the polymorphic method would run logic to check if it’s owned then show a view which tells the current player how much they owe. However if it is for sale then show a view which shows how much it is to buy with two options to the user 1. Buy 2. Don’t buy

However if we land on a chance, using polymorphism something totally different will occur, all I have to do in my controller or my model is call action() for the logic. It works fine.

Now. My problem

How from the model can I decide what view should be rendered ? An option is to put all the logic in the controller and get the current type of square! But that’s messy and will consist of a lot of conditionals. E.g.

If(typeOfSquare === chance ){
// get the latest chance and call a     
View method to render it with options to the user 
}

I would rather use polymorphism and have and build my logic of the square in seperate classes. E.g ChanceSquae or PropertySquare but that would mean building a property on the square called something like htmlView which will store the html that I can get from the square object and then pass into the view.

This seems like an impossible situation to deal with without getting messy!!

1 Answer 1

1

You're on the right track here about what kind of code to avoid.

If your game board works with a list of base Tile object without knowing which is which, the game board cannot reasonably judge how to display a tile since the correct display hinges on the specific tile that it is.

In this case, the board should ask the tile what to render, because the tile knows itself. (Note: I am going to do a more MVC-oriented solution afterwards, this is a basic solution to show the underlying principle at play without MVC specifics)

Something along the lines of:

public abstract class Tile
{
    public abstract Image GetImage();
}

public class FreeParkingTile : Tile
{
    public Image GetImage() => Image.FromFile("FreeParking.png");
}

public class RailwayTile : Tile
{
    // Indicates which of the four railways it is
    public RailwayEnum Type { get; }

    public Image GetImage() => this.Type switch
    {
        RailwayEnum.KingsCross  => Image.FromFile("KingsCross.png"),
        RailwayEnum.Marylebone  => Image.FromFile("Marylebone.png"),
        RailwayEnum.FenchurchSt => Image.FromFile("FenchurchStreet.png"),
        RailwayEnum.LiverpoolSt => Image.FromFile("LiverpoolStreet.png"),
    };

    // Alternatively, if the filename matches the enum:
    public Image GetImage() => Image.FromFile($"{Type}.png");
}

Now, your game board doesn't need to know the specific tiles, because it can just call myTile.GetImage() and be done with it. This maintains the intentional ignorance of the board logic, ensuring that it never needs to know any specifics about any tile in particular.


Since you're working in MVC, instead of returning an image you could be returning a partial view path. This SO answer shows you how it can be done (I leave the adjustments to the above code I added as an exercise).

Adapted for your use case:

@foreach (var tile in Model.Tiles)
{
    Html.RenderPartial(tile.PartialViewPath)
}

Another possible solution, this SO answer shows you how you can use MVC's DisplayFor to your advantage, by building display templates for each individual tile type and then having DisplayFor render the correct template for the correct tile.

Adapted for your use case:

@page
@model MonopolyBoardModel

@foreach (var tile in Model.Tiles)
{
    @Html.DisplayFor(t => tile, tile.GetType().Name)
}

I personally prefer the DisplayFor solution, but as you can see there are several ways in which you can tackle this.

7
  • I thank you so much for your comprehensive answer. I will have to study this. I am not familiar with Java syntax , only JavaScript! And also the how to understand the conceptual implementation of this code. Commented Nov 14, 2022 at 2:09
  • @KevinGreetham It's C#, and I now realize I blindly assumed you were using ASP.Net MVC; my bad. But the overall advice still applies :) That being said, JS is not a particularly solid implementation of OOP in my opinion and this might impact what you can reasonably achieve without making it significantly more complex. I'm not a JS dev so I'll leave that to others.
    – Flater
    Commented Nov 14, 2022 at 2:37
  • Haha. Sorry. Man, I’m such a novice. I’ve been staring at the first SO link you gave me. Ok so In JavaScript there is a built in function called eval() which reads a string as a line of code. Is this similar to the partial view way you have described? E.g. the string I want call eval() on will have a path to the view function I want to call. And the string can include any other data that I want to pass into the view as an argument? Or am I barking up the wrong tree? Commented Nov 14, 2022 at 3:10
  • @KevinGreetham: I can't judge what the correct way to do it in JS is. In regards to the code I added, you store the views (i.e. html components) in separate files, and can then tell the renderer to render a specific view by naming it. In this example, the name of the view would be defined in the tile, e.g. "/Tiles/FreeParking". The MVC engine can take it from there and passes the tile to the view, which in turn renders the HTML based on the tile's content (if applicable, e.g. to print the name of the railway station)
    – Flater
    Commented Nov 14, 2022 at 4:14
  • Ahhh. I would love to be able to do that but not an option in JS. Imports must be at the top of the page!! You cannot dynamically import when you need to! 😩 Commented Nov 14, 2022 at 19:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.