Home > Back-end >  Correctly abstracting the model from the view in an MVC Design Pattern
Correctly abstracting the model from the view in an MVC Design Pattern

Time:07-03

I am developing a simple CandyCrush lookalike game in C to familiarise myself more with OOP and Design Patterns, namely MVC.

The general structure of the Model is as such : UML Diagram of Model design

My idea is to use a 'packaging' logic, such that each GameComponent can be 'packaged' into a primitive type representation.

For example, a RedCandy object would be represented by "R" when packaged.

When needed, the Control will 'package' the model by packaging all the individual GameComponents and returning the results as a matrix of strings. This matrix is then communicated to the View.

The string constants that represent each type of GameComponent are stored in a static class Constants with the following structure :

class Constants {
    static const std::string RED;
    static const std::string BLUE;
    static const std::string GREEN;
    static const std::string YELLOW;
    static const std::string PURPLE;
    static const std::string ORANGE;

    static const std::string WALL;
    static const std::string BOMB;

    static const std::array< std::string, 6 > candies;
public:

    static const std::string getRED() {return RED;}
    static const std::string getBLUE() {return BLUE;}
    static const std::string getGREEN() {return GREEN;}
    static const std::string getYELLOW() {return YELLOW;}
    static const std::string getPURPLE() {return PURPLE;}
    static const std::string getORANGE() {return ORANGE;}

    static const std::string randomCandy() {return candies[rand() % 6];}

    static const std::string getWALL() {return WALL;}
    static const std::string getBOMB() {return BOMB;}
};

Thus, when the view interprets packaged Model, it refers to the Constants class.

Would this be a correct way of abstracting the model ? Or am I overthinking it ?

CodePudding user response:

Yes I think you may be overthinking things! Adhering to MVC in the most generic sense just means that your data and logic (the model) are independent of the user interface code, which has the view and controller components. Additionally, you could think of individual objects as models, to be rendered in individual views: a player can be a model, represented by a name and a score, the list of available moves can be a model, shown as clickable images, etc.

So in your specific example, the GameBoard class would be what models the state of the game, presumably as part of some Game class that governs the updates to its cells. As long as these classes are only concerned with game logic and others deal with, for example, loading images and responding to mouse clicks, then you have a MVC application. No further abstractions are inherently necessary.

A bare minimum implementation could have something like:

#include <memory>
#include <string>
#include <vector>

struct GameComponent
{
    virtual ~GameComponent() = default;
    virtual std::string type() const = 0;
};

struct Candy : public GameComponent
{
    std::string type() const override { return "candy_"   m_colour; }
    
private:
    std::string m_colour {"red"};
};

using GameBoard = std::vector<std::vector<std::unique_ptr<GameComponent>>>;

Of course you may choose to keep the additional classes shown in your scheme, but this should be enough of an interface to allow a corresponding view class to show nothing for nullptr elements, or use the string representation provided by type() to load an image. A basic design for views and controllers could be:

struct BoardView
{
    // functions to draw the board given model data, highlight something
    // under the mouse cursor, etc.
private:
    GameBoard* m_model;
};

struct Game;

struct GameController
{
    // functions to convert mouse input in the view to actions on the game,
    // tell the view to notify the player of invalid input, update view
    // after valid input, etc.

private:
    Game* m_model;
    BoardView* m_view;
};

This is just to show one example of a MVC-like structure. Different interpretations exist, such as that views should not communicate directly with models, but strictly get their input from controllers, making them another separate layer. But unless you are tied to one of those, you're allowed to be pragmatic and do whatever suits you!

The real implementation would depend on the library you choose for designing the GUI. For example, I'm most familiar with Qt, which is a model/view framework with no separate controller concept. Therefore, Qt views do interact directly with their models.

  • Related