3

I'm trying to implement function objects in Java. I have a Unit class, with a default addition function that should be used in most initializations of a Unit object. However, for some issues, I need a different addition function. The code will look something like this:

public class Unit() {
   public Unit(unitType) {
      if (unitType == "specialType") {
         additionFunc = defaultFunc } else {
         additionFunc = specialFunc }
      }
   }
   public int swim() {
      return additionFunc()
   }
  // definiion of regularFunc
  // definition of specialFunc

}

Then, from the main file:

Unit fish = new Unit(regularTyoe);
Unit fatFish = new Unit(specialType);
fish.swim(); //regular function is called
fatFish.swim(); //special function is called

That's it.. does anyone know how this can be done?

7 Answers 7

4

You need to look up inheritance and method overriding. It would probably help to read up on proper Object Oriented Programming as well.

The proper way to do this is:

class Fish {
  public void swim() {
    // normal swim
  }
}

class FatFish extends Fish {
  @Override
  public void swim() {
    // special swim
  }
}

Fish fish = new Fish()
Fish fatFish = new FatFish()
fish.swim()    // normal swim
fatFish.swim() // slow swim
Sign up to request clarification or add additional context in comments.

2 Comments

is this the only way? no function objects in java? :((
@n00bprogrammer .... functions are not first-class object in Java. While there are ways to hack what you're trying to do, it's the wrong approach on every level.
2

Make a new FatFish class which extends Unit and overrides swim().

Unit fish = new Unit();
Unit fatFish = new FatFish();
fish.swim(); //regular function is called
fatFish.swim(); //special function is called

Comments

2

There are many solutions for your problem, one of them is using inheritance, that you could have a default implementation of Unit, and extend it overriding the desired method with a new one.

Basically would be something like:

public class FatFish {
    @Override
    public void swim() {
        // new behavior 
    }
}

Another approach would be to implement Strategy Design Pattern, which allows you to select algorithms on runtime. Therefore you could do something like:

public interface SwimStrategy {
    void execute();
}

public class FatFishSwimStrategy implements SwimStrategy {
    @Override
    public void execute() {
        // fat fish swim impl
    }

}

public class FishSwimStrategy implements SwimStrategy {
    @Override
    public void execute() {
        // normal fish swim impl
    }

}

public class Fish {

    private final SwimStrategy swimStrategy;

    public Fish(SwimStrategy swimStrategy) {
        this.swimStrategy = swimStrategy;
    }

    public void swim() {
        swimStrategy.execute();
    }

}

In order to instantiate an object you could do:

new Fish(new FatFishSwimStrategy());

or for the normal behavior:

new Fish(new FishSwimStrategy());

1 Comment

I think your interface SwimStrategy should have void swim() instead of void execute()?
1

I think it can do by extends and factory method:

public class Unit {

public static Unit createUnit(UnitType type) {
    if (UnitType.Special == type) {
        return new Unit(type) {
            @Override
            public int swim() {
                System.out.println("special swim");
                return 0;
            }
        };
    }
    return new Unit(UnitType.Default);
}

private UnitType type;

private Unit(UnitType type) {
    this.type = type;
    System.out.println("create unit for " + type);
}

public int swim() {
    System.out.println("default swim");
    return 0;
}

public static void main(String[] args) {
    Unit fish = Unit.createUnit(UnitType.Default);
    Unit fatFish = Unit.createUnit(UnitType.Special);
    fish.swim();
    fatFish.swim();

}

}

This is a simple type enum:

public enum UnitType { Default, Special

}

1 Comment

All these answers make me feel noober than ever :) This seems to be the closest to what I need, thanks!
1

There are two ways to accomplish this polymorphic behavior in Java. The first is to use a inheritance and a hierarchical set of classes. For example, you could have an abstract base class which defines an abstract method called "swim". Then each concrete fish class would extend this base class and implement the swim method. Later when you have a set of fish objects, you can upcast them to the base class and invoke the swim method on each.

The second way is to use interfaces. You define an interface (e.g. ISwim) which declares the public method swim. Each fish class (whether part of a class hierarchy or no) would implement the ISwim interface, meaning they would define a swim method. Then if you have a set of fish class objects of different types, you can cast each to the ISwim interface and invoke the swim method on each object.

Java does not have function pointers, so the approach you are considering is inappropriate for the language. Even in languages with function pointers, the above two approaches would be most appropriate in my opinion.

Comments

1

One way to do this is with an enum for the types of Unit and with Unit subclasses:

public class Unit {
    public enum UnitType {
        REGULAR {
            public Unit makeUnit() {
                return new RegularUnit();
            }
        },
        SPECIAL {
            public Unit makeUnit() {
                return new SpecialUnit();
            }
        };
        abstract public Unit makeUnit();
    }
    protected Unit() {}
    public abstract int swim();
    private static class RegularUnit extends Unit {
        RegularUnit() {}
        public int swim() {
            return 0;
        }
    }
    private static class SpecialUnit extends Unit {
        SpecialUnit() {}
        public int swim() {
            return 1;
        }
    }
}

Unit fish = UnitType.REGULAR.makeUnit();
Unit fatFish = UnitType.SPECIAL.makeUnit();

Another way is with Callable objects:

public class Unit {
    public enum UnitType { REGULAR, SPECIAL }
    private Callable<Integer> additionFunc;
    public Unit(UnitType type) {
        switch (type) {
        case REGULAR:
            additionFunc = new Callable<Integer>() {
                public Integer call() {
                    return 0;
                }
            };
            break;
        case SPECIAL:
            additionFunc = new Callable<Integer>() {
                public Integer call() {
                    return 1;
                }
            };
            break;
        }
    }
    public int swim() {
        return additionFunc();
    }
}

Comments

1

Using a simple if statement:

private String unitType;

public Unit(unitType) {
    this.unitType = unitType;      
}

public int swim() {
    if (unitType.equals("specialType") {
        return specialFunc();
    }
    else {
        return regularFunc();
    }
}

Or using polymorphism and a factory method :

public abstract class Unit() {

    protected Unit() {
    }

    protected abstract int addition();

    public int swim() {
        return addition();
    }

    public static Unit forType(String unitType) {
        if (unitType.equals("specialType") {
            return new SpecialUnit();
        }
        else {
            return new RegularUnit();
        }
    }

    private static class SpecialUnit extends Unit {
        @Override
        protected addition() {
            // special addition
        }
    }


    private static class RegularUnit extends Unit {
        @Override
        protected addition() {
            // regular addition
        }
    }
}

Or using an Adder functional interface, defining an addition() method, and two concrete implementations of this interface:

private Adder adder;

public Unit(unitType) {
    if (unitType.equals("specialType") {
        this.adder = new SpecialAdder();
    }
    else {
        this.adder = new RegularAdder();
    }  
}

public int swim() {
    return adder.addition();
}

This last one is the closest to waht you asked in your question. function objects don't exist per se, but can be replaced by interfaces.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.