Two important considerations which have not been mentioned are whether gene1.geneDistance(gene2) is always expected to match gene2.geneDistance(gene1), and whether Gene is and always will be a sealed class. Instance methods are polymorphic with respect to the types of the things upon which they are invoked, but not the types of their arguments. This can cause some confusion if the distance function is supposed to be transitive, but things of different types might compute distance differently. If the distance function is supposed to be transitive, and is defined as being the shortest transformation that either class knows about, a good pattern may be to have a protected instance method int getOneWayDistance(Gene other)
and then have something like:
public static int geneDistance(Gene g0, Gene g1)
{
int d0=g0.getOneWayDistance(g1);
int d1=g1.getOneWayDistance(g0);
if (d0 < d1) return d0; else return d1;
}
Such a design will ensure that distance relation behaves transitively, while allowing individual types to report shortcuts to instances of other types that those other types may not know about.