Getting the distance between various classes of shapes Below I define a simple shape class with two derived classes: Point and Line which both implement the Distance interface that defines a getDistance(Shape) method.  This type of setup could be useful for calculating distances between shapes.  For this simple example, consider the distance to be in 1D space and don't consider the actual calculations.  

package shape;

public interface Distance {
    public int getDistance(Shape other);
}

public abstract class Shape implements Distance {
    public abstract int getDistance(Shape shape);
    public abstract int getDistance(int num); //for point
    public abstract int getDistance(int start, int end); //for line
}


public class Line extends Shape {
    private int start;
    private int end;

    public Line(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public int getDistance(Shape other) {
        return other.getDistance(start, end);
    }

    //never gets called
    public int getPoint(Point other) {
        return getDistance(other.num);
    }

    @Override
    public int getDistance(int num) {
        return Math.min(Math.abs(num - start), Math.abs(num - end));
    }

    @Override
    public int getDistance(int start, int end) {
        int delta1 = Math.min(Math.abs(this.start - start), Math.abs(this.start - end));
        int delta2 = Math.min(Math.abs(this.end - start), Math.abs(this.end - end));
        return Math.min(delta1, delta2);
    }
}

public class Point extends Shape {
    protected int num;

    public Point(int num) {
        this.num = num;
    }

    @Override
    public int getDistance(Shape other) {
        return other.getDistance(num);
    }

    @Override
    public int getDistance(int num) {
        return Math.abs(this.num - num);
    }

    @Override
    public int getDistance(int start, int end) {
        return Math.min(Math.abs(num - start), Math.abs(num - end));
    }
}

public class ShapeTest {
    public static void main(String[] args) {
        Shape line = new Line(1, 2);
        Shape point = new Point(0);
        System.out.println(line.getDistance(point));
    }
}


My question is with the implementation above, there's a lot of indirection.  For example, in the Line and Point classes, for the following method: public int getDistance(Shape other), it's not known at compile time what Shape actually is.  So to avoid doing instanceof on Shape and handling each case in that function, I call getDistance on other and pass in the relevant coordinates -- this is the indirection that's a bit ugly, but it's a more object-oriented / polymorphic approach than casting and instanceof.  

Question is: is there a cleaner way to implement this?  I'd like to define the required function int getDistance(Shape), leave it empty, and then define getDistance(Line) and getDistance(Point).  With those functions defined, it would be nice if Java just always called the most specific function prototype (so that getDistance(Shape) is never actually called), but that doesn't seem to happen.  

Any advice on how to clean up the code above?
Quick Comments

Your Distance Interface is weird. It does not represent a distance, but an object having the ability to provide the distance between it, and some other object sharing the same interface.

The Shape interface is weird. The distance(int) and distance(int, int) are hacky and should go. They rely on implementation details of Point and Line.

The Shape should be an interface. It is currently a void Abstract class with no added value, it just prevents proper inheritance.

It looks weird to me to return ints for distances, given the propension of most metrics to return doubles due to frequent square roots being applied. However, I don't know your metrics so I'll stick with it.



Implementation using double-dispatch

If the number of classes is rather low, you could implement double-dispatch. Make the Shape interface have a distance(Shape) and every distanceTo(Foo), distanceTo(Bar), distanceTo(Fuzz) etc. like so:

public interface Shape {
    int distance(Shape shape);
    int distanceTo(Foo foo);
    int distanceTo(Bar bar);
    int distanceTo(Fuzz fuzz);
}


This way all Shape implementations will look like the following:

public class Foo implements Shape {
    public int distanceTo(Shape shape) {
        // You can copy-paste this method body on all other classes
        return shape.distanceTo(this); // This will call the strongly-typed methods below
    }
    public int distanceTo(Foo foo){
        // Specific implementation
    }
    public int distanceTo(Bar bar){
        // Specific implementation
    }
    public int distanceTo(Fuzz fuzz){
        // Specific implementation
    }
}


Here's how to use it:

Foo foo = new Foo();
Bar bar = new Bar();
int foobar = foo.distance(bar);
int foofoo = foo.distance(foo);


Very simple with just 3 classes. Can become a nightmare with 10+ classes.

You have to realize, that for every pair of Shapes, you'll need a dedicated distance method implementation. This means the number of distance(T t, U u) methods will grow rapidly.

From here on I will assume your network of Shape objects is sufficiently complex to warrant a dedicated structure to handle this in an externalized way.



The Problem

Basically, this boils down to the following:


  Given miscelaneous Objects, how to make it possible for any pair of Objects to interact (the interaction depends on the nature &amp; implementation of those objects, and is not known in advance) and return something.


Obviously the interaction between two entities cannot be entirely contained in the entities themselves. 

If it was, each Entity would have to know its distance to any other entity type (including unknown &amp; unforeseen future Shape implementations), which means it would know every other Entity existence, and implementation details, and would have a dedicated distance implementation for each. That would:


Break Encapsulation - one Entity would have to know the detailed implementation of the other to perform the calculation)
Break extensibility - Adding an Foo entity would require adding a distance(Foo)method to every other Object


All those sins were commited in the double-dispatch implementation above.
So now we know the interaction implementation has to be externalized.



How to build an extensible externalized interaction function

Let's have a centralized distance functor (I'll make it a Singleton using an Enum, I assume you only have one set of interacting Shape implementations):

public enum DistanceEvaluator {
    INSTANCE;
    public final int distance(Shape shape1, Shape shape2){
         // Do something magic here
    }
}


Is this usable enough? I think you could very easily add the following default method (thanks, Java 8) to your Shape Interface:

public interface Shape {
    default int distance (Shape other){
        return DistanceEvaluator.INSTANCE.distance(this, other);
    }
}


Now aShape can calculate its distance to an other... provided the DistanceEvaluator holds an implementation for that particular pair of classes.



Enriching the DistanceEvaluator with implementations

A) You could implement everything in the DistanceEvaluator.

Then you just distribute the implementation using ìnstanceof and casting.
Advantages: The class combines all implementations, so can make good reuse of helper intermediate functions.
Disadvantage: the class could become enormous. 

This should be used if the number of pairs is rather small with synergies (points, lines, segments, polygons).

B) You could use instanceofand cast the first argument (of type Foo)

Then simply forward the second argument (type Bar) to a FooDistanceCalculator class that knows how to compute distance to any Bar class.
Advantage: Implementations are grouped in a package, yet distributed between several classes.
Disadvantage: how to tell if distance(Foo, Bar) or distance(Bar, Foo) exists?

This should be used if the number of pairs becomes important and requires a (simple) structure.

C) You could make a completely dynamic mapping of distance functions.

Such mapping could be enriched at runtime, as a bonus.

Use the following Evaluator :

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;

public enum DistanceEvaluator {

    INSTANCE;

    /** Holds distance implementations */
    private final Map&lt;Class&lt;? extends  Shape&gt;, Map&lt;Class&lt;? extends Shape&gt;, BiFunction&lt;? extends Shape, ? extends Shape, Integer&gt;&gt;&gt; MAP = new HashMap&lt;&gt;();

    /** When a class has no matching map of distance functions */
    private final Map&lt;Class&lt;? extends Shape&gt;, BiFunction&lt;? extends  Shape, ? extends  Shape, Integer&gt;&gt; MISSING = new HashMap&lt;&gt;();

    /** When a pair has no matching distance function */
    private final BiFunction&lt;? extends  Shape, ? extends  Shape, Integer&gt; NO_FUNCTION = new BiFunction&lt;Shape,Shape, Integer&gt;() {
        @Override
        public Integer apply(Shape t, Shape u) {
            throw new IllegalArgumentException("Shapes " + t + " and " + u + " cannot calculate their respective distance");
        }
    };


    /**
     * Computes the distance between any pair of Shapes.
     * @param shape1 a shape
     * @param shape2 another shape
     * @throws IllegalArgumentException if the pair has no matching distance implementation
     * @return the distance between the two shapes
     */
    public &lt;T extends Shape, U extends Shape&gt; int distance(T shape1, U shape2) {
        @SuppressWarnings("unchecked")
        Class&lt;T&gt; shape1class = (Class&lt;T&gt;) shape1.getClass();
        @SuppressWarnings("unchecked")
        Class&lt;U&gt; shape2class = (Class&lt;U&gt;) shape2.getClass();
        @SuppressWarnings("unchecked")
        BiFunction&lt;T,  U, Integer&gt; func = (BiFunction&lt;T, U, Integer&gt;) MAP.getOrDefault(shape1class, MISSING).getOrDefault(shape2class, NO_FUNCTION);
        return func.apply(shape1, shape2);
    }

    /** Register a distance function for a pair of {@link Shape} sub-classes. 
     * Note the function will be registered for both class pairs (a, b) and (b, a)
     * @param class1 first {@link Shape} Class
     * @param class2 second {@link Shape} Class
     * @param biFunction distance {@link BiFunction}
     */
    public &lt;T extends Shape, U extends Shape&gt; void register(Class&lt;T&gt; class1, Class&lt;U&gt; class2, BiFunction&lt;T, U, Integer&gt; biFunction) {
        Map&lt;Class&lt;? extends Shape&gt;, BiFunction&lt;? extends Shape, ? extends Shape, Integer&gt;&gt; intermediate1 = MAP.get(class1);
        if(intermediate1 == null){
            intermediate1 = new HashMap&lt;&gt;();
            MAP.put(class1, intermediate1);
        }
        intermediate1.put(class2, biFunction);

        // Symmetric
        Map&lt;Class&lt;? extends Shape&gt;, BiFunction&lt;? extends Shape, ? extends Shape, Integer&gt;&gt; intermediate2 = MAP.get(class2);
        if(intermediate2 == null){
            intermediate2 = new HashMap&lt;&gt;();
            MAP.put(class2, intermediate2);
        }
        intermediate2.put(class1, biFunction);
    }
}


Here are a few Shape implementations. Note those implementations inject their required distance evaluators when their classes are loaded.

A Point class:

public class Point implements Shape{
    static {
        DistanceEvaluator.INSTANCE.register(Point.class, Point.class, new BiFunction&lt;Point, Point, Integer&gt;() {
            @Override
            public Integer apply(Point t, Point u) {
                return 0; // Calculations here
            }
        });
        DistanceEvaluator.INSTANCE.register(Point.class, Line.class, new BiFunction&lt;Point, Line, Integer&gt;() {
            @Override
            public Integer apply(Point t, Line u) {
                return 0; // Calculations here
            }
        });
    }
    // Class implementation details, up to you
}


A Line class:

public class Line implements Shape {
    static {
        DistanceEvaluator.INSTANCE.register(Line.class, Line.class, new BiFunction&lt;Line, Line, Integer&gt;() {
            @Override
            public Integer apply(Line t, Line u) {
                return 0; // Calculations here
            }
        });
    }
    // Class implementation details, up to you
}


With this scheme, it becomes possible to not implement all distance functions. This might or might not be a good feature for you.