1

Is there a way to create a class that has a method that can change with each instance of that object?

What I want to use this for is a class called Dice that has the method roll(int s), which returns a random number from 1 to s, is there a way to make it so other instances of Dice to have variations of roll(int s), such as a weighted die, only returns numbers > or < half of s, etc. that isn't inheritance or interfaces?

EDIT: I'm not opposed to using inheritance, I'd just prefer a more condensed version that doesn't have 10+ classes with slightly different roll and toString methods being the only difference

  • Have you tried creating methods with the same name, but different parameters? Or would this not accomplish your task? – Chris Gong Dec 20 '15 at 02:21
  • @DaneBrick That wouldn't solve my problem -- I'm looking for the same method to be called by another class in the same way each time, but have a slightly modified approach at returning an integer. I think a good way to explain it would be having the class take a method as a parameter and use *that* for the roll method. – GoonyKnightMan Dec 20 '15 at 02:25

3 Answers3

2

Use function object

public class Dice {
    final BiFunction<Random, Integer, Integer> roll;
    final Random random = new Random();

    public Dice(BiFunction<Random, Integer, Integer> roll) {
        this.roll = roll;
    }

    public Dice() {
        this((r, n) -> r.nextInt(n) + 1);
    }

    public int roll(int n) {
        return roll.apply(random, n);
    }
}

public static void main(String[] args) {
    Dice normal = new Dice();
    Dice alwaysTwo = new Dice((r, n) -> 2);
    Dice gaussian = new Dice((r, n) -> (r.nextInt(n) + r.nextInt(n) + 2) / 2);
}
  • This approach has a name: the [Strategy Pattern](https://en.wikipedia.org/wiki/Strategy_pattern). I think it's the best solution for this type of problem. – Erwin Bolwidt Dec 20 '15 at 03:57
0

Inheritance would be the prefered way, but as you asked for it:

You can store your variations in a member variable of Dice and set it in the constructor or via an own function called like setVariation(DICE_VARIATiON variation).

So each Dice object would remember how the dice should be handled.

enum DICE_VARIATION{ NORMAL, LOW_HALF, HIGH_HALF }

public class Dice
{
  private DICE_VARIATION _variation;
  public Dice(DICE_VARIATION variation)
  {
    _variation = variation;
  }

  public int roll(int s)
  {
    switch(_variation)
    {
      case DICE_VARIATION.NORMAL:
          return /*normal random return*/
      case DICE_VARIATION.LOW_HALF:
          return /*random return from 1 to s/2*/
      case DICE_VARIATION.HIGH_HALF:
          return /*random return from s/2 to s*/
    }
    return -1;
  }
}

You can create some objects like new Dice(DICE_VARIATION.NORMAL); or new Dice(DICE_VARIATION.LOW_HALF);

Boardwish
  • 495
  • 3
  • 16
  • I think use a field to indict the type of a instance is not a good idea. Inheritance might be better. – VicX Dec 20 '15 at 02:29
  • @VicX: GoonyKnightMan asked for a way without inheritance – Boardwish Dec 20 '15 at 02:30
  • Sorry, I didn't notice that. If that I think your solution is quite good. Make that `enum` an inner class of `Dice` might be even better. – VicX Dec 20 '15 at 02:33
  • Thank you! I'd like to make it possible to have some have several variations, such as (being able to roll low have AND a 50% chance of being rolled again. If I were to make a DICE_VARIATION array, could I loop through that and have a slightly modified body of what roll currently has applying all the "filters" on the number before returning it? – GoonyKnightMan Dec 20 '15 at 02:39
  • You can loop over it, see http://stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values. I don't know exactly what you mean with "filters", but I guess you have to store your variation somewhere to query them afterwards. – Boardwish Dec 20 '15 at 02:47
0

I don't really know if I used interfaces or not but I have 0 reputation and I wanted to provide a solution to your answer that wasn't already posted (as if I could have created those anyway).

There's only one class so I don't know if that counts as inheritance? But you have to construct a switch statement for each type of dice roll you want.

public class Dice{

private int whoodat; //whoodat is the result of the rolls for each Dice instance

    public int roll (int s, int dieType){

        float low = 1;
        float high = 4;
        //assuming 4 sided die are lowest conventional die size

        switch(dieType){
            case 1: low = s/2; high = s; break; 
            case 2: low = 0; high = s/2; break;
            case 3: low = 1; high = s; break;
            default: low = 1; high = s; break;      
        }

        int view = (int) processing.core.PApplet.map(
                ((float)Math.random()), ((float)0.0), ((float)1.0), low, high);
        return view;                    
    }

//Roll method that accepts parameters from a Dice constructor
//and does the work you want for weighting a die.


    public Dice(int maxInt, int dieType){
        super();
        whoodat = roll(maxInt, dieType); 
        System.out.println(whoodat);

    }
//Constructor to create each Dice object. You must pass in the max sides of
 //the dice and the type of dice you want to roll (how it's weighted).


    public static void main(String[] args){
        Dice jobby = new Dice(4000, 1);
        Dice cappy = new Dice(9000, 2);
        Dice pappy = new Dice(20, 3);

//This is jobby cappy and pappy, testers for the program.
CLC
  • 1
  • 1