Are there any hard and fast rules on the use of this pattern or is it solely intended as a way to achieve additional functionality within method calls without using inheritance?
I have amended the example below that I took from a SO post to demonstrate what I am considering.
public interface Coffee {
public double getCost();
public String getIngredients();
}
public class SimpleCoffee implements Coffee {
#Override
public double getCost() {
return 1;
}
#Override
public String getIngredients() {
return "Coffee";
}
}
public class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
#Override
public double getCost() {
//you can add extra functionality here.
return decoratedCoffee.getCost();
}
#Override
public String getIngredients() {
//you can add extra functionality here.
return decoratedCoffee.getIngredients();
}
public boolean methodNotDefinedInInterface() {
//do something else
return true;
}
}
So with the example above in mind, is it viable to:
a) use the simple Coffee whenever you see fit without decorating it
b) Add additional functionality that is not defined in the Coffee interface to decorator objects such as the methodNotDefinedInInterface()
Could someone also explain where the composition comes into this pattern as the SimpleCoffee is something that can exist in its own right, but it seems to be the decorator that actually 'owns' any object.
Although without the SimpleCoffee class (or some concrete implementation of Coffee) the decorator doesnt have any purpose, so aggregation doesnt seem to be what is occurring here.
The description of the pattern includes intent which makes it pretty clear what the pattern is for:
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time.
As for "hard and fast rules" - I generally don't think that there are "hard and fast rules" in patterns at all. Like, if you don't implement it exactly as GoF described, there will be no "pattern police" punishing you. The only point is that if you follow the classic guidelines, other developers will have less problems recognizing patterns in your code.
Your example is quite OK from my point of view.
SimpleCoffee is not a decorator, so no composition there. CoffeeDecorator has decoratedCoffee as a component (here you have your composition)
a) use the simple Coffee whenever you see fit without decorating it
Yes, of course.
b) Add additional functionality that is not defined in the Coffee
interface to decorator objects such as the
methodNotDefinedInInterface()
You can add more methods just like adding new methods to SimpleCoffee class, but note that you would need to use those additional methods somewhere in the decorator class.
Personally, I find this pattern useful when someone gives you an instance of Coffee (i.e. you didn't instantiate it). If you need to change its behavior at runtime, the only way is to wrap it inside another object of Coffee type. This is when you can throw it into the decorator class. The decorator can expose some of the original behavior while providing some new behaviors.
Consider this interface
public interface IDoSomething {
void DoAAA();
void DoBBB();
void DoCCC();
}
and these two implementations
public class MyObject1 implements IDoSomething {
public MyObject(int a, xObjx x)
..
}
public class MyObject2 implements IDoSomething {
public MyObject(int a, xObjx x)
..
}
How can I not expose the implementation classes to other developers? Specifically how can I prevent the following?
IDoSomething C = new MyObject2();
Is using a factory class the best practice?
public class DoSomethingFactory {
static IDoSomething getDoSomething(int a, xObjx x) {
...
}
}
How can I extend this pattern to include implementations that have different constructors?
If you're always going to be constructing the MyObject1/2 instances in your own code, you might be able to make them package private (default permissions). A "builder" pattern might make sense too.
Can you maybe elaborate on how / why it matters if the constructors of the objects are exposed? Interfaces just define functionality requirements, not construction requirements.
Good software is written on a need to know basis. The more ignorant a component is about how its companion classes get the job done the better. That is purpose that interfaces serve. They allow willfully ignorant programmers to write code on a need to know basis.
One problem is a programmer that wants to know can almost always know. Even if you could prevent the assignment which you can't, they can cast the obfuscated object into its implementation, inspect its properties and methods with reflection, or pipe the jar into a hex editor. This isn't really something you can stop.
What you can do is write code that makes the lives of need to know programmers easier, clearly communicates the intention of your design, and reduces the temptation for programmers to cheat(using dirty implementation details as a crutch). The best way accomplish this is to use Creational Patterns.
In reference to your point about constructors being different this is handled nicely by all the basic creational patterns. Because they provide an abstraction over the constructor. You get to decide how much or how little detail to expose. Maybe you have a constructor like the one below:
public ColorThing(int r ,int g, int b)
that accepts numeric color values. In your implementation of a creational pattern you might decide to simplify this by making the constructor private and only allowing access to a static factory method.
private ColorThing(int r , int g, int b){
...
}
public static ColorThing buildRedColorThing(){
return new ColorThing(100,0,0);
}
This would limit consumers of your ColorThing class to only being able to construct red things.
Listed below are several basic creational patterns that sort of do what you want. They provide varying degrees of obfuscation building up to the Abstract Factory Pattern which yields the highest degree of encapsulation but also requires the most boiler plate.
Static Factory Method
This is the guy from the ColorThing example above. This simply provides a public static method on the class that protects the nitty gritty details of the constructor. Great for simplifying access to a constructor with lots of parameters. In this case, you can make your constructor private and provide as many static factory methods as you need.
public class MyObject1 implements IDoSomething {
private int prop a;
public static IDoSomething getAnObject(int a){
return new MyObject(a, new xObjx());
}
private MyObject(int a, xObjx x)
...
}
The Builder Pattern
The builder pattern has an accompanying class responsible for creating your class. It uses java's scope rules to ensure that the constructor is accessed in a secure fashion. This is also very useful if you want to have a lot of telescoping constructor args because you can rely on dot chaining of the methods of the builder class (new MyObject1.MyObjectBuilder().setA(2).build())
public class MyObject1 implements IDoSomething {
private int prop a;
private MyObject1(int a, xObjx x)
...
public class MyObjectBuilder {
private int a;
public MyObjectBuilder setA(int a){
this.a = a;
return this;
}
public IDoSomething build(){
return new MyObject1(a, new xObjx);
}
}
}
Abstract Factory
The Abstract Factory Pattern allows you to completely encapsulate the construction of a class. This will only every expose the interface, but it also has the most boiler plate because you have to create a Factory and a set of Product implementations and interfaces for each family of classes you want to manufacture. Here is a text book example of how the classes in this pattern relate. This pattern is highly extensible and you will see it used to great effect in lots of library code. This is because the designers of these libraries commonly don't know the full set of implementations their framework code will need to support. By using an Abstract Factory Pattern they can let future developers build on their code while limiting the restrictions imposed by their assumptions.
Which one you pick will be entirely contingent on your circumstances, but you should start with the simplest one that satisfies your needs and work your way to the more complex ones.
When laying out a class hierarchy, I often find myself frustrated at the gap between being able to encapsulate functionality while also sharing code. Part of the problem, of course, is lack of multiple inheritance, but interfaces help somewhat. The inability to define protected methods on interfaces seems to me to be the bigger issue.
The standard solution seems to be to have a public interface that is implemented by a protected abstract base class. The problem is when we have the following
public interface Foo {
public String getName();
}
abstract protected BaseFoo implements Foo {
abstract protected int getId();
private String name;
protected BaseFoo(String name) {
this.name = name;
}
#Override
public String getName() {
return this.name;
}
}
public class ConcreteFoo extends BaseFoo {
public ConcreteFoo (String name) {
super(name);
}
#Override
protected int getId() {
return 4; // chosen by fair dice roll.
// guaranteed to be random.
}
}
// in the foo package with the classes above
public class FooCollection {
private static Map<Integer, Foo> foos = new HashMap();
public static void add(Foo foo) {
synchronized(foos) {
foos.put(foo.getId(), foo); // can't call foo.getId()
}
}
}
// client code, not in the foo package
FooCollection.add(new ConcreteFoo("hello world"));
That is, we return one of our nicely-encapsulated objects to caller, but then any method which gets that object back needs to be able to rely on some internal functionality. That internal functionality cannot be part of the interface (that would break encapsulation), but to make it part of an abstract base class requires us to use casting.
We cannot make Foo an abstract class because other interfaces need to extend it to add optional, orthogonal functionality to a more complex hierarchy than is display here.
What are the standard approaches to this problem? Do you add getId to the Foo interface, even though clients shouldn't use it? Do you perform an unsafe cast to BaseFoo in FooCollection.add? If you check before casting, what do you do when the types don't match, even though they always should for all intents and purposes?
Any information you have on best practices in this sort of situation would be very helpful.
Edit: In case it's not clear, this example is intentionally oversimplified. The key point is that sometimes you return an "interface view" of an object. When that "interface view" is passed back in to a package-specific class, the method it is passed to will likely need to use internal functionality in its implementation. How does one manage that mismatch between internal and public functionality?
Okay, here's a couple of points:
Contrary to popular opinion, inheritance really isn't about sharing code. What you create in an inheritance hierarchy is an organization of things that share some common set of abstract behaviors; it just works out sometimes to have the effect of reusing some code.
The fashion has changed quite a bit in the last few years, so that deep and complicated inheritance hierarchies are no longer considered good form. In general in Java. you should
use aggregation before implementing an interface
use interfaces to express "mix-in" contracts
use inheritance only if the classes describe something that has natural inheritance.
If you really want the effect of multiple inheritance, build implementation classes for your interfaces, and aggregate them.
In particular, by defining your classes with interfaces and implementation classes, you make building tests much easier; if your interface is separate, it's almost trivial to build a mock for that interface.
I don't know about "best" practices, but here are a couple of ideas.
Interfaces are supposed to separate "what is to be done" from "how something is to be done". I don't think getters and setters belong in interfaces. I try to give them more meaningful signatures.
In your case, I see nothing wrong with two interfaces:
public interface Nameable {
String getName();
}
public interface Identifiable {
int getId();
}
Separate the two; force clients to implement only the ones they need. Your decision to make id part of the abstract class is arbitrary. Separating it out and making it explicit can be helpful.
Casting loses all benefit of polymorphism. I don't think that it should be abandoned lightly. If you must move getId() up to the interface, do so. If you can avoid it by different choices, do so.
"Best" depends on your context. Your simple example might not be true in all cases.
I am trying to incorporate more functional programming idioms into my java development. One pattern that I like the most and avoids side effects is building classes that have behavior but they don't necessarily have any state. The behavior is locked into the methods but they only act on the parameters passed in.
The code below is code I am trying to avoid:
public class BadObject {
private Map<String, String> data = new HashMap<String, String>();
public BadObject() {
data.put("data", "data");
}
/**
* Act on the data class. But this is bad because we can't
* rely on the integrity of the object's state.
*/
public void execute() {
data.get("data").toString();
}
}
The code below is nothing special but I am acting on the parameters and state is contained within that class. We still may run into issues with this class but that is an issue with the method and the state of the data, we can address issues in the routine as opposed to not trusting the entire object.
Is this some form of idiom? Is this similar to any pattern that you use?
public class SemiStatefulOOP {
/**
* Private class implies that I can access the members of the <code>Data</code> class
* within the <code>SemiStatefulOOP</code> class and I can also access
* the getData method from some other class.
*
* #see Test1
*
*/
class Data {
private int counter = 0;
public int getData() {
return counter;
}
public String toString() { return Integer.toString(counter); }
}
/**
* Act on the data class.
*/
public void execute(final Data data) {
data.counter++;
}
/**
* Act on the data class.
*/
public void updateStateWithCallToService(final Data data) {
data.counter++;
}
/**
* Similar to CLOS (Common Lisp Object System) make instance.
*/
public Data makeInstance() {
return new Data();
}
} // End of Class //
Issues with the code above:
I wanted to declare the Data class private, but then I can't really reference it outside of the class:
I can't override the SemiStateful class and access the private members.
Usage:
final SemiStatefulOOP someObject = new SemiStatefulOOP();
final SemiStatefulOOP.Data data = someObject.makeInstance();
someObject.execute(data);
someObject.updateStateWithCallToService(data);
Edit-1: This is a good comment. My response: "As soon as you make the Data class accessible outside the main class you are exposing implementation details, " -- comment.
My Response: The Data class is a simple POJO and will work like other pojos with setters and getters. What I was doing in the class above was trying to only manipulate the Data class from the behavior class, SemiStatefulOOP. I do intend to have stateless classes but I wanted to have a clear separation from the state classes and the behavior classes.
Related:
Stateless Design Pattern
http://guides.brucejmack.biz/Pattern%20Documents/Stateless%20Design%20Pattern.htm
There's an interesting OO architectural style that aims to separate the data and the behavior of a system, so that they can evolve independently: the DCI Architecture.
In practice, you create data objects for your domain concepts (possibly only with simple behavior related to the data itself); and behavior objects that work with the data objects and that realize the use cases of the system. These behavior objects are seen as roles that the domain objects can play, and are materialized with the OO concept of a trait (pdf).
Scala has traits, but Java doesn't. You can try to use the Qi4J framework in Java for that.
One of the key points of OO programming is that you hide implementation details. Your approach doesn't seem to be doing that - as soon as you make the Data class accessible outside the main class you are exposing implemntation details, and effectively exposing data representation.
It is of course impossible to make all classes stateless - something has to hold the state, and it's not clear to me why holding it in Data is preferable to holding it in the main class.
Finally a principle of OO programming is to keep data and functionality related to it in the same place, i.e. the same class. In short, while your proposal is interesting, I think the problems it creates are worse than the problems it solves.
building classes that have behavior
but they don't necessarily have any
state
See wiki
The strategy pattern is intended to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms vary independently from clients that use them.
// The context class uses this to call the concrete strategy
interface Strategy {
int execute(int a, int b);
}
// Implements the algorithm using the strategy interface
class ConcreteStrategyAdd implements Strategy {
public int execute(int a, int b) {
System.out.println("Called ConcreteStrategyAdd's execute()");
return a + b; // Do an addition with a and b
}
}
I'm not sure I understand quite what you're asking here. As an alternative to BadObject's statefulness, could you not simply declare the method as
public void execute(Map<String, String> data) {
...
}
or similar?
In general, when I think of functional and/or stateless idioms, the overwhelming code pattern that crops up is to have methods take parameters for everything they depend on (instead of getting them from fields or static methods or train wrecks (getFoo().getCustomer().getAddress().getHouseName())). That and return the result, rather than modifying the state of other objects.
At this point, all the data classes can be immutable since there's nothing to modify, which makes the code much easier to understand and reason about.
This wouldn't be one of the original GoF patterns, but I believe Josh Bloch has a paragraph on this in Effective Java entitled something like "Prefer immutability", which is catchy enough.
I think that the best solution to incorporate more functional programming into your projects is to use a functional programming language, like Scala. Scala is fully interoperable with Java and compatible with JVM. Scala classes is Java classes and vise versa. Why not to try it... :)
Java is full OOP language and my opinion is that functional paradigms just doesn`t fit nicely into it.
It looks like you have utility classes.
public class Data {
private static final Map<String, String> data = new HashMap<String, String>();
static {
data.put("data", "data");
}
private Data() { }
/**
* Act on the data class.
*/
public static void execute() {
data.get("data").toString();
}
}
You don't need to create an object.
Data.execute();
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I have a Gene class that keeps track of genes. Gene has a method for calculating the distance between two genes. Are there any reasons to make it static?
Which is better?
public static int geneDistance(Gene g0, Gene g1)
or
public int geneDistance(Gene other)
Arguments for/against making it static? I understand what it means for a member to be static, I'm just interested in its implications for maximum cleanliness/efficiency/etc.
I repeat the same pattern for returning trimmed versions of two genes, finding matches between genes, finding matches between animals (which contain collections of genes), etc.
Instance, not static
For this case I think the second choice is clearly better. If you think about it, any method could be implemented as static if you are willing to pass the object to it, this only seems to be a special case because the other parameter is also an instance.
Therefore, our search for symmetry and abstraction is slightly offended by having to choose between the two instance objects for the dot operator. But if you look at .method as . then operator, it isn't really a problem.
Plus, the only way to do functional-style chaining is with an attribute, i.e., instance method. You probably want thing.up.down.parent.next.distance(x) to work.
When you make a method static, it means that the method can be called without an instance of the class. It also means that the method cannot access instance variables unless it is passed a reference to an object.
Sometimes, it makes sense to make a method static, because the method is associated with the class, but not a particular instance of the class. For example, all the parseX methods, such as Integer.parseInt(String s). This converts a String to an int, but does not have anything to do with a particular instance of an Integer object.
If, on the other hand, a method must return some data which is unique to a particular instance of an object, (like most getter and setter methods), then it can't be static.
IMO there is no absolute "better", but public int geneDistance(Gene other) is stylistically more similar to other methods in Java (e.g. Object.equals, Comparable.compareTo), so I'd go that way.
I prefer the second form, i.e. instance method for the following reasons:
static methods make testing hard because they can't be replaced,
static methods are more procedural oriented (and thus less object oriented).
IMO, static methods are ok for utility classes (like StringUtils) but I prefer to not abuse using them.
My rewording of Charle's answer :
If the method in question intends to use the state of the underlying object in any way, make it an instance method. Else, make it static.
Which depends on the way the object's class is designed.
In your case, alphazero, probably the int geneDistance(Gene g0, Gene g1) does not really depend on the state of the Gene instance it is called on. I would make this method static. And put it in a utility class like GeneUtils.
Of course, there might be other aspects of your problem that I am not aware of, but this is the general thumb of rule that I use.
P.S. -> The reason I would not put the method in the Gene class itself is because a Gene should not be responsible for computing it's distance from another Gene. ;-)
public static int geneDistance(Gene g0, Gene g1) would be part of a separate utility class like Collections and Arrays in Java whereas public int geneDistance(Gene other) will be part of the Gene class. Considering you have other operations like "trimmed versions of two genes, finding matches between genes, finding matches between animals (which contain collections of genes), etc" I would create a separate static utility class for them as these operations aren't semantically meaningful to what a Gene is.
If the the semantics of "gene distance" can be wrapped up into your equals(Object o) method then you could consume it there or else include it in your static utility.
I would like to start answering on your question with the new one: What your class Gene is responsible for? May be you have heard about the 'Single-Responsibility Principle': A class should have only one reason to change. So, I believe if you answer this question you will be able to decide how your application should be designed. In this particular case, I would not use neither the first approach nor the second one. In my opinion it is much better to define new responsibility and encapsulate it in a separate class or may be a function.
I'll try to sum up some of the points already given here to which I agree.
Personally I don't think there is a "feels better" answer. Valid reasons do exist on why you don't wan't a utility class filled with static methods.
The short answer is that in an object oriented world you should use objects and all the good "stuff" that comes with them (encapsulation, polymorphism)
Polymorphism
If the method for calculating the distance between the genes varies, you should roughly (more likely a Strategy) have a Gene class per variation. Encapsulate what varies. Else you will end up with multiple ifs.
Open For Extension, Closed for Modification
That means that if a new method for calculating the distance between genes comes up down the line, you shouldn't modify existing code, but rather add new one. Else you risk breaking what's already there.
In this case you should add a new Gene class, not modify the code written in the #geneDistance
Tell Don't Ask
You should tell your objects what to do, not ask them for their state and make decisions for them. Suddenly you break the single responsibility principle since that's polymorphism.
Testability
Static methods may well be easy to test in isolation, but down the road you will make use of this static method in other classes. When it comes to testing that classes on isolation, you will have hard time doing it. Or rather not.
I'll let Misko have his saying which is more likely better than what I can come up with.
import junit.framework.Assert;
import org.junit.Test;
public class GeneTest
{
public static abstract class Gene
{
public abstract int geneDistance(Gene other);
}
public static class GeneUtils
{
public static int geneDistance(Gene g0, Gene g1)
{
if( g0.equals(polymorphicGene) )
return g0.geneDistance(g1);
else if( g0.equals(oneDistanceGene) )
return 1;
else if( g0.equals(dummyGene) )
return -1;
else
return 0;
}
}
private static Gene polymorphicGene = new Gene()
{
#Override
public int geneDistance(Gene other) {
return other.geneDistance(other);
}
};
private static Gene zeroDistanceGene = new Gene()
{
#Override
public int geneDistance(Gene other) {
return 0;
}
};
private static Gene oneDistanceGene = new Gene()
{
#Override
public int geneDistance(Gene other) {
return 1;
}
};
private static Gene hardToTestOnIsolationGene = new Gene()
{
#Override
public int geneDistance(Gene other) {
return GeneUtils.geneDistance(this, other);
}
};
private static Gene dummyGene = new Gene()
{
#Override
public int geneDistance(Gene other) {
return -1;
}
};
#Test
public void testPolymorphism()
{
Assert.assertEquals(0, polymorphicGene.geneDistance(zeroDistanceGene));
Assert.assertEquals(1, polymorphicGene.geneDistance(oneDistanceGene));
Assert.assertEquals(-1, polymorphicGene.geneDistance(dummyGene));
}
#Test
public void testTestability()
{
Assert.assertEquals(0, hardToTestOnIsolationGene.geneDistance(dummyGene));
Assert.assertEquals(-1, polymorphicGene.geneDistance(dummyGene));
}
#Test
public void testOpenForExtensionClosedForModification()
{
Assert.assertEquals(0, GeneUtils.geneDistance(polymorphicGene, zeroDistanceGene));
Assert.assertEquals(1, GeneUtils.geneDistance(oneDistanceGene, null));
Assert.assertEquals(-1, GeneUtils.geneDistance(dummyGene, null));
}
}
Here's a meta-answer, and a fun exercise: survey a bunch of the Java SDK's library classes and see if you can categorize the commonalities between static methods in different classes.
In this particular case, I will make it an intance method. BUT if you have a logical answer when g0 is null then use BOTH (this happen more often than you think).
For example, aString.startsWith(), if the aString is null, you may think it is LOGICAL to return null (in case you think the function can be NULL-TOLERATE). This allows me to simplify my program a bit as there is no need to have aString check null in the client code.
final Stirng aPrefix = "-";
final Vector aStrings = new Vector();
for(final String aString : aStrings) {
if (MyString.startsWith(aString, aPrefix))
aStrings.aStringadd();
}
instead of
final Stirng aPrefix = "-";
final Vector aStrings = new Vector();
for(final String aString : aStrings) {
if ((aString != null) && aString.startsWith(aPrefix))
aStrings.aStringadd();
}
NOTE: This is an overly simplified example.
Just a thought.
I would make this an instance method. But that might be due to the fact that I have no clue of genes ;)
Instance methods can be overridden by subclasses which greatly reduces the complexity of your code (less need for if-statements). In the static method example, what will happen I you get a specific type of gene for which the distance is calculated differently? Ad another static method? If you'd have to process a polymorphic list of genes you'd have to look a the type of gene to select the correct distance method... which increases coupling and complexity.
I'd select the second approach. I see no advantage in making the method static. Since the method is in the Gene class, making it static only adds one extra parameter with no extra gain. If you need a util class, that's a whole different deal. But in my opinion there's usually no need for a util class if you can add the method to the class in question.
I think the problem domain should inform the answer beyond the general stylistic and/or OO considerations.
For example, I'm guessing that for the domain of genetic analysis, the notions of 'gene' and 'distance' are fairly concrete and will not require specialization through inheritance. Were that not the case, one could make a strong case for opting for the instance methods.
The main reason to prefer the instance method is polymorphism. A static method cannot be overridden by a subclass, which means you can't customize the implementation based on the instance type. This might not apply in your case, but it is worth mentioning.
If gene distance is completely independent of the type of the gene, I would prefer using a separate utility class to make that independence more explicit. Having a geneDistance method as part of the Gene class implies that distance is a behavior related to the gene instance.
My answer is very opinionated.
I would go the same way as one of the StringUtils.getLevenshteinDistance implementation in StringUtils.
public interface GeneDistance{
public int get();
}
public class GeneDistanceImpl implements GeneDistance{
public int get(){ ... }
}
public class GeneUtils{
public static int geneDistance(Gene g0, Gene g1){
return new GeneDistanceImpl(g0, g1).get();
}
}
Some points for doing it this way
There might be several distance implementations, so an utility method is more preferable than g0.distanceTo(g1)
I can static-import it for a short notation
I can test my implementation
I can also add this:
class Gene{
// ... Gene implementation ...
public int distanceTo(Gene other){
return distance.get(this, GeneUtils.getDefaultDistanceImpl());
}
public int distanceTo(Gene other, GeneDistance distance){
return distance.get(this, other);
}
}
One of the reasons to make a complex method completely static is the performance. static keyword is a hint for a JIT compiler that the method can be inlined. In my opinion you s/he don't need to bother about such things unless their method calls are almost instantaneous - less than a microsecond, i.e. a few string operations or a simple calculation. This might be the reason why Levenshtein distance was made completely static in the latest implementation.
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.