patternjavaMinor
Use of static factory methods for vectors and matrices library
Viewed 0 times
vectorsfactorymethodsforlibrarymatricesandusestatic
Problem
I've been working on a Java-based mathematics library focusing on vectors and matrices. I plan to use it for an important upcoming project, so the classes are analogous to data types available in GLSL (e.g. Vector2 for GLSL's vec2, Matrix4 for GLSL's mat4, and so on).
I'm trying to only expose interface to clients (e.g.
However, there's something I currently don't like too much and I'm wondering if there's a way to improve the code design to address it.
Here's what the interface looks like (I've omitted the non-static methods for brevity because they're not relevant to the question):
I'll briefly note that:
```
final class Vect
I'm trying to only expose interface to clients (e.g.
Vector2) and keep implementation classes package-private (e.g. Vector2f). I'm trying to use the static factory methods and, since I'm using Java 1.8, I'm trying to take advantage of the new option that allows static methods to be added to interfaces.However, there's something I currently don't like too much and I'm wondering if there's a way to improve the code design to address it.
Here's what the interface looks like (I've omitted the non-static methods for brevity because they're not relevant to the question):
public interface Vector2 extends Measurable, Bufferable {
static Vector2 createZeroVector() {
return Vector2f.createZeroVector();
}
static Vector2 createFrom(float x, float y) {
return Vector2f.createFrom(x, y);
}
static Vector2 createFrom(double x, double y) {
return Vector2f.createFrom(x, y);
}
static Vector2 createFrom(final float[] values) {
return Vector2f.createFrom(values);
}
static Vector2 createFrom(final double[] values) {
return Vector2f.createFrom(values);
}
static Vector2 createNormalizedFrom(float x, float y) {
return Vector2f.createNormalizedFrom(x, y);
}
static Vector2 createNormalizedFrom(double x, double y) {
return Vector2f.createNormalizedFrom(x, y);
}
static Vector2 createNormalizedFrom(final float[] values) {
return Vector2f.createNormalizedFrom(values);
}
static Vector2 createNormalizedFrom(final double[] values) {
return Vector2f.createNormalizedFrom(values);
}
// ... non-static methods omitted ...
}I'll briefly note that:
```
final class Vect
Solution
To put it simply, you're using the wrong language elements to achieve your goals.
The purpose of interfaces is to serve as a contract.
They define a set of actions that implementations must be able to perform.
Although Java 8 made it possible to add
it's best when an interface contains no implementation at all.
Before adding
think twice, and question yourself if there's a better way.
In this example,
it seems quite clear that all those
that would be best in a utility class.
There's no point putting them anywhere else if they cannot be extended or overridden.
So it would be better to extract these to a
And why does a
What does that even mean?
It seems like this interface is trying to do too much.
I strongly suspect violations of the single responsibility principle in your implementation.
Why does an interface know about any implementations at all? It really shouldn't.
Why would a client expect a specific implementation from a method that returns an interface type? It really shouldn't.
You seem deeply confused. I recommend further reading on the subject:
-
In Effective Java by Joshua Bloch (in this order):
-
Consider a related pattern used by
-
Consider a related pattern used by
The purpose of interfaces is to serve as a contract.
They define a set of actions that implementations must be able to perform.
Although Java 8 made it possible to add
static and default methods to an interface (and I'll have to read up on why they did that),it's best when an interface contains no implementation at all.
Before adding
static or default methods,think twice, and question yourself if there's a better way.
In this example,
it seems quite clear that all those
createFrom* methods are in fact utility methods,that would be best in a utility class.
There's no point putting them anywhere else if they cannot be extended or overridden.
So it would be better to extract these to a
Vector2dUtils class or similar.And why does a
Vector2d extend Bufferable and Measurable?What does that even mean?
It seems like this interface is trying to do too much.
I strongly suspect violations of the single responsibility principle in your implementation.
- the interface class knows about a specific implementation and can only return
Vector2finstances, and
Why does an interface know about any implementations at all? It really shouldn't.
- a client expecting a
Vector2dimplementation class gets aVector2finstead!
Why would a client expect a specific implementation from a method that returns an interface type? It really shouldn't.
You seem deeply confused. I recommend further reading on the subject:
-
In Effective Java by Joshua Bloch (in this order):
- Item 19: Use interfaces only to define types
- Item 17: Design and document for inheritance or else prohibit it
- Item 18: Prefer interfaces to abstract classes
- Item 16: Favor composition over inheritance
-
Consider a related pattern used by
java.util.Collections (source code), in particular the facilities provided by methods like .emptyList, .unmodifiableList, .synchronizedList-
Consider a related pattern used by
java.util.EnumSet (source code), especially how its various factory methods create either RegularEnumSet or a JumboEnumSet depending on what is appropriate given the input params, and the client just doesn't need to know whatever is the actual implementation.Context
StackExchange Code Review Q#82257, answer score: 4
Revisions (0)
No revisions yet.