Unarelith
Unarelith

Reputation: 495

Is SRP related to possible actions of a single class or to their implementation in it?

I've read in a lot of places that SRP is a good principle to apply, and I wanted to apply it in my projects.

Actually, it's a game, and my objects have basically two functions update and draw, so they have two responabilities (defined as a "reason to change"). It could look like this:

class Object {
    public:
        void update() {
            // implementation...
        }

        void draw() {
            // implementation...
        }
};

Let's say I choose to use the Component design pattern to split update and draw into an UpdateComponent and a DisplayComponent, the object which uses these component will still have the pair update/draw, but not their implementations anymore. So it could look like this now:

class Object {
    public:
        void update() {
            m_updateComponent.update(*this);
        }

        void draw() {
            m_displayComponent.draw(*this);
        }

    private:
        UpdateComponent m_updateComponent;

        DisplayComponent m_displayComponent;
};

In this implementation, are update and draw considered as responsabilities of the components and of the object, or only the components so the object agrees with the SRP?

Upvotes: 0

Views: 267

Answers (1)

weston
weston

Reputation: 54781

You have considered the "reason to change" and moved it. Now if either the drawing or updating needs to change, you do not need to change the Object class. That is all inline with SRP.

However, you have some unnecessary coupling. You can tell because of the two way dependancy between DisplayComponent and Object. Why does the Object need to know about (depend upon) its DisplayComponent or even it's UpdateComponent?

You have:

DisplayComponent <--> Object

(the lines represent a dependency, i.e. you can't compile one without the other it is pointing at)

You only need:

DisplayComponent ---> Object

But then how would you get to the DisplayComponent to call draw, if you can't do that from the object?

ObjectContainer          --\ 
   --> UpdateComponent   ---> Object
   --> DisplayComponent  --/

So I have introduced a new ObjectContainer class that knows about (depends upon) UpdateComponent, DisplayComponent and Object.

Your outer game loop only has access to ObjectContainers and can only change game state via m_updateComponent and draw via m_displayComponent. Object's only responsibility now is to persist the state of the object:

class Object {
    public:
      //getters/setters maybe

    private:
        int x;
        int y;
        float speed;
        float health;
        //etc
};

class ObjectContainer {
    public:
        void update() {
            m_updateComponent.update(object);
        }

        void draw() {
            m_displayComponent.draw(object);
        }

    private:
        Object object;

        UpdateComponent m_updateComponent;

        DisplayComponent m_displayComponent;
};

The above ObjectContainer is very similar to your Object, but there is no two-way dependency.

Upvotes: 1

Related Questions