Jorjon
Jorjon

Reputation: 5434

Extract a behavior from an object

I have a class which is becoming a God Object. In this game, it manages the main Game Scene itself, which should be the reason why it is becoming this large.

But there are some portions of this class that I can group together. Specifically, they deal with a special mode which is triggered randomly in the game.

I want to know what would be the best approach to separate this behavior and turn it into an Object. I'm lost here, since this is a behavior and not a "thing", so I can't think of a nice and elegant solution.

class Game
    var lives = 1
    var score = 0
    var time = 0

    doStuff() {}
    doMoreStuff() {}
    specialActivate() {}
    specialUpdate() {}
    specialInput() {}
    specialDeactivate() {}

As you can see, there are many "special mode" related functions. Problem is that some of these functions rely on the variables and methods contained in Game.

  1. Create a new class and send in the needed variables and callbacks together in a Context (or Model) object.

    class Game
        var lives = 1
        var score = 0
        var time = 0
        var special = new Special(new SpecialContext(lives, score, time, doStuff))
    
        doStuff() {}
        doMoreStuff() {}
    
    class Special
        var context:SpecialContext
    
        constructor(context:SpecialContext)
            this.context = context
    
        activate() {}
        deactivate() {}
        input() {}
        update() {}
    
    class SpecialContext
        var lives
        var score
        var time
        var doStuff:Callback
    
        constructor(lives, score, time, callbackDoStuff:Callback)
            this.lives = lives
            this.score = score
            this.time = time
            this.doStuff = callbackDoStuff
    
  2. Create an interface and make Game implement that interface, to protect Game.

    class Game implements IGameSpecial
        var lives = 1
        var score = 0
        var time = 0
        var special = new Special(this)
    
        doStuff() {}
        doMoreStuff() {}
    
    class Special
        var game:IGameSpecial
    
        constructor(gameSpecial:IGameSpecial)
            this.game = game
    
        activate() {}
        deactivate() {}
        input() {}
        update() {}
    
    interface IGameSpecial
        doStuff()
        getLives()
        setLives()
        getTime()
        setTime()
        getScore()
        setScore()
    
  3. Send directly the game class (the dirty approach).

    class Game
        var lives = 1
        var score = 0
        var time = 0
        var special = new Special(this)
    
        doStuff() {}
        doMoreStuff() {}
    
    class Special
        var game:Game
    
        constructor(gameSpecial:Game)
            this.game = game
    
        activate() {}
        deactivate() {}
        input() {}
        update() {}
    

Is there an elegant way to solve this? Does this problem have a name or a pattern associated to it?

Upvotes: 0

Views: 114

Answers (2)

Daniel T.
Daniel T.

Reputation: 33978

You mention a "special mode", presumably that is opposed to the "normal mode". "Mode" is (or at least can be) a type, which would suggest using the State pattern. However, it doesn't look as though you have any sort of type code in the class to tell whether these 'special' methods should be used, so I'm assuming that there is something outside the class that decides that.

I expect that you could decompose the 'special' methods into simpler methods on the Game class. This implies that you could have the "special mode" be a Decorator that is applied to the Game at appropriate times. Whether this would work depends heavily on how the Game class is used.

Upvotes: 2

Matei Florescu
Matei Florescu

Reputation: 1195

I would do this:

1) Create an interface:

interface ISpecialAction {
    execute()
}

2) implement it for every special action:

class Activation implements ISpecialAction {
    setLives()
    setTime()
    execute()
}

3) delegate in class Game to this classes

class Game {

    specialActivate() {
         Activation a = new Activation()
         a.execute()
    }

}

This decouples the special actions from the Game class, so you will not have a God class anymore in what is concerning special actions. The interface implemented by the special action classes can help for example when using a Factory or a Builder to create the special actions.

Upvotes: 1

Related Questions