1

I've created a Vector2D class that extends Point2D.Double.

A Vector2D has two fields: magnitude and direction. The extension of Point2D.Double allows the vector to store a starting location as well.

I like the ability to do this:

Vector2D myVector = new Vector2D(50, 50);  // instantiated without direction or magnitude
Point2D.Double myPoint = new Point2D.Double(myVector.getLocation());

However, I'd like to disallow this:

Point2D.Double myPoint = myVector;

And this:

Point2D.Double myPoint.setLocation(myVector);

Because both of these operations treat a myVector as if it is just a Point2D.Double.

I know that Java doesn't allow overriding or overloading of operators, so the first undesired case seems especially difficult to eliminate. I also know that I can override .setLocation() with an empty method body (to prevent its use), but that's not really a great solution.

Is there a way to disallow Vector2D methods or operators that exist in Point2D.Double?

Peter
  • 4,021
  • 5
  • 37
  • 58

3 Answers3

3

I'm failing to see the issue here. If you want Vector2D to be a subclass of Point2D.Double, then you are explicitly declaring that it IS a Point2D.Double. If the client wants to use it as a Point2D.Double that is allowed, and completely legitimate.

It sounds like what you are trying to accomplish is subclassing as a code reuse system, rather than as a true is-a relationship. This is generally considered an anti-pattern.

Either accept that clients can do this (even though you dislike it), or switch to a composition object instead.

jsight
  • 27,819
  • 25
  • 107
  • 140
1

No, there is no way to disallow this.

You can, however, try a non-inheritance approach using a Vector field wrapped with your specific functionality. One drawback is this would not allow you to accommodate the following functionality you mentioned:

Vector2D myVector = new Vector2D(50, 50);  // instantiated without direction or magnitude
Point2D.Double myPoint = new Point2D.Double(myVector.getLocation());

Not sure there is a clean way to handle this. I wonder what your use case is that you need this sort of behavior.

John Ericksen
  • 10,995
  • 4
  • 45
  • 75
1

This is not possible at the type level due to how Java's subtype system works and the Liskov substitution principle. (There are other languages, like Eiffel, which do allow this pattern!)

Liskov's notion of a [behavioral] subtype defines ... if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering [that program] ....

If inheritance is used the best that can be done is throwing a "Not Supported Exception" or, as pointed out, doing nothing. (Note this actually violates LSP which includes behavioral correctness as a requirement!)

If multiple discreet interfaces were used -- but they aren't here -- then it would be possible to pick'n'choose which interfaces to implement (which could be done with composition). However, with composition (or an otherwise unrelated type) one can't use a custom Vector2D as a Point2D.Double and thus Java shows how easy it is to get into a bind with subtypes ;-) I lean towards multiple specialized interfaces these days.

If explicit conversions are acceptable, then Vector2D.fromPoint2D(...) and Vector2D.toPoint2D(...) is one approach that may be tolerable...

Happy coding.

Community
  • 1
  • 1