Design Patterns – Is Experimenting with Them a Good Idea?

cdesigndesign-patternsengineeringgame development

I have been reading a lot about different design patterns, their pros, cons, main usage etc. However, I like to experiment and try to invent my own ways of the implementations (even if they are not the best). Now I am facing a problem with my Entity component system implementation.

Despite of the pros of this pattern I want to do some of the things in my own way, for example:

1.) Components are wrapped into bigger interfaces for data manipulation. In most of the cases i read that ECS components must contain only data and the systems are their main manipulators. In my system I intend to use a wrapper classes for the components

Little example: Lets say we want to have a Sprite component, that represents the visual component of each entity in game. I wrapped it inside the RenderableEntity class that can be a component of an entity and has additional functions and variables.

2.) I don´t use a system for every type of component.

Again an example from game engine : We have a CollidableEntity, that is put in some spatial data structure and doing its collision checks, but for RenderableEntity there is no system that manages it (I assume that we are in 2D now). Reason? I want the user to have the power of rendering the sprites of each entities, because of specific order or using different batches.

3.) Entities can have more than 1 component of the same type and no bitsets are used for checking if is the system interested in given entity. The components are assigned to systems at their creation via the data type.

Little code:

template<class DataType>
DataType* createComponent(GameEntity* mainEntity)
{
    //Create it via default constructor
    DataType* component = new DataType();

    //Add it to the back of the component vector
    mainEntity->_entityComponents.emplace_back(component);

    //Assign it to system
    ECS::assignToSystem<T>(component);

    //Return it to access its functions
    return component;
}

The assignToSystem function does following : checks if is the given data type in our map and if not, it adds the component to the system and from now is the system the maintainer of the component. Also the gamesystems are attached to given data types via a function and it looks like this :

class ColliderSystem:public ECS::System
{
    void assignSystem() override
    {
        ECS::assignSystemToComponent<CollidableEntity>(this);
    }
};

Can you tell me if its a good idea to experiment with given patterns and try to do things your own way? Especially I care about this because want to use this approach in my graduation work and wonder if it will be a problem if I "break rules" of some patterns. Also , what do you think about my "changes", are there any cons? Thanks.

Best Answer

People have experimented with different mechanics of implementing a design pattern in the past with differing results. For example, the definition of a singleton is that there is only one instance of a class for your entire application. There is nothing in that definition that requires you to implement it with a static accessor, even though that's how the example in the GoF book is written. Folks that use components like the Spring framework let the component container guarantee that there is only one instance and a reference to that instance is injected everywhere you need access.

That example leads to a few points:

  • If what you are doing is fundamentally different from the pattern, call it something different. There is nothing worse than two people using the same words that are talking about different concepts. Nothing but confusion happens after that.
  • If what you are doing is following the pattern, make sure your differences are actually solving a problem. Being different just to be different is not helpful 9 times out of 10.
  • "playing" with implementation details can help you understand the pattern better, and why the example code looks the way it does.
  • Mixing all the patterns into one project leads to an incomprehensible mess. Just use what you need to use.

At the end of the day, no user is going to praise your judicious use of the flyweight pattern or even know that you used a decorator pattern in there somewhere. Patterns are called that because they are common solutions to common problems that happen to have very similar implementations. Many times the details of the implementation are less important than the concept that inspired it. Just make sure that your code is comprehensible to someone else, or even your future self 3 months down the road.

I'm not going to get preachy, but I will encourage you to look at the impact of what you are doing as objectively as you can. Users only care that the application/game/tool/etc. works. Developers on your team care about whether they can understand it and fix it when they find things that are broken. Every time you deviate from the norm, it increases the amount of time it takes to understand the code. Make it annoying enough and your development team will rewrite everything so that it is more familiar.

Related Topic