0

Here is the working java code to provide a base engine class which handles the balance listener registration, for a number of engine implementations used by various games. e.g. there would be a demo engine which maintains a demo balance for a demo game and a cash version of the same engine which gets the balance from a back office etc. The crux here is not the actual java, but how to implement this kind of pattern in JavaScript. i have tried about 30 different ways to do it, including using John Resigs "simple JavaScript inheritance" and the extend() sugar defined in "JavaScript: The definitive Guide", using various module patterns, using that=this etc. none of which worked for this problem.

Here is the working java code:

File Engine.java:

package com.test;
public abstract class Engine {
    BalanceListener externalBalanceListener = null;
    double balance = 0;
    public void registerBalanceListener(BalanceListener balanceListener) {
        externalBalanceListener = balanceListener;
        balanceListener.update(balance);  // call once when first register
    }
    public double getBalance() {
        return balance;
    }
    protected void setBalance(double newBal) {
        if (newBal != balance) {
            balance = newBal;
            if (externalBalanceListener != null) {
                externalBalanceListener.update(newBal);
            }
        }       
    }
    public abstract double startGame(double stake, int numLines);
}

File BalanceListener.java

package com.test;
public interface BalanceListener {
    void update(double balance);
}

File DemoEngine.java

package com.test;
import java.util.Random;

public class DemoEngine extends Engine {
    public DemoEngine() {
        setBalance(10000);
    }
    public double startGame(double stake, int numLines) {
        double wonAmount;
        Random random = new Random();

        setBalance (getBalance() - (stake * numLines));

        // some game logic
        wonAmount = Math.round((random.nextDouble() * 10)) * stake;
        setBalance (getBalance() + wonAmount);          
        return wonAmount;
    }
}

File DemoGame.java

package com.test;

public class DemoGame {

    public class MyListener implements BalanceListener {
        public MyListener(){
        }
        public void update(double balance) {
            System.out.println("new balance: " + balance);
        }
    }

    public static void main(String[] args) {
        Engine engine = new DemoEngine();

        DemoGame demoGame = new DemoGame();

        BalanceListener balanceListener = demoGame.new MyListener();

        engine.registerBalanceListener(balanceListener);

        engine.startGame(10, 20);
    }
}

Here was a plain (failed) attempt to get the same thing working in JavaScript (see http://jsfiddle.net/fmX67/ )

function Engine() {
    this.balance = 0;
    this.externalBalanceListener;

    this.registerBalanceListener = function(l) {
            this.externalBalanceListener= l;
            this.externalBalanceListener(this.balance);
    };

    this.getBalance = function() {
        return this.balance;
    };

    this.setBalance = function (newBal) {
        if (newBal != this.balance) {
            this.balance = newBal;
            if (this.externalBalanceListener != undefined) {
                this.externalBalanceListener(newBal);
            }
        }
    };

};

function DemoEngine() {
    this.startGame = function(stake, numLines) {
        var won;

        setBalance(this.getBalance() - stake*numlines);
        won = Math.round(Math.random() * 10) * Stake;

        this.setBalance(this.getBalance() + won);

        return won;
    };
}

DemoEngine.prototype = Engine;

function DemoGame() {

    function balanceListener(balance) {
        console.log(balance);
    }

    var engine = new DemoEngine();

    engine.registerBalanceListener(balanceListener); // This throws an exception: Uncaught TypeError: Object [object Object] has no method 'registerBalanceListener'

    engine.startGame(10, 25);
}

var game = new DemoGame();

Obviously I have no idea what I am doing (despite reading several JS Books). I assume I could use composition instead of trying to inherit, but this limits the use of the language and what patterns can be implemented.

Edit: here is the working version with Shaun West's answer. see http://jsfiddle.net/fmX67/3/

function Engine() {
    this.balance = 0;
    this.externalBalanceListener;

    this.registerBalanceListener = function(l) {
            this.externalBalanceListener= l;
            this.externalBalanceListener(this.balance);
    };

    this.getBalance = function() {
        return this.balance;
    };

    this.setBalance = function (newBal) {
        if (newBal != this.balance) {
            this.balance = newBal;
            if (this.externalBalanceListener != undefined) {
                this.externalBalanceListener(newBal);
            }
        }
    };

};

function DemoEngine() {
    this.setBalance(1000);
    this.startGame = function(stake, numLines) {
        var won;

        this.setBalance(this.getBalance() - stake*numLines);
        won = Math.round(Math.random() * 10) * stake;

        this.setBalance(this.getBalance() + won);

        return won;
    };
}

DemoEngine.prototype = new Engine();

function DemoGame() {

    function balanceListener(balance) {
        console.log(balance);
    }

    var engine = new DemoEngine();

    engine.registerBalanceListener(balanceListener); // This throws an exception: Uncaught TypeError: Object [object Object] has no method 'registerBalanceListener'

    engine.startGame(10, 25);
}


var game = new DemoGame();
John Little
  • 10,707
  • 19
  • 86
  • 158

1 Answers1

1

As odd as it may seem to someone coming from Java, in your attempt you'll want to change this:

DemoEngine.prototype = Engine;

To this:

DemoEngine.prototype = new Engine();

This answer is pretty good if you want more information: What is the 'new' keyword in JavaScript?

Community
  • 1
  • 1
Shaun West
  • 91
  • 2
  • Result, that worked! Still baffled by JS inheritance (yes I'm a Java dev), despite wading through all the classic (impenetrable) JS books and articles. My brain is not big enough to get all the required JS language concepts in it at the same time (java inheritance is trivial by comparison). – John Little Jul 18 '13 at 12:23