/* * ACKNOWLEDGMENTS *
- Kipp Johnson suggested the term reduced angle.
- Prof. Kevin Wayne offered several ideas/thoughts/suggestions:
Subject: Re: p. 453: access to instance variables in a superclass... From: Kevin Wayne
Date: Tue, 20 Mar 2018 17:00:35 -0400 Cc: Bob Sedgewick To: John Spurgeon Hi John. Yes, designing data types is a challenging task! I think the Angle data type is a nice data type example because there are two natural representations (radians and degrees), much like complex (where there are rectangular and polar representations) and there are several interesting operations. For angles, I think the big difference is that you are really modeling different units (rather than a different underlying representation—number of turns). I like the public isCongruent() and isCoterminal() methods - not as sure about minPosCoterminal(), maxNegCoterminal(), and minSizeCoterminal(), as they create new objects (and do not seem to be as directly useful).
A few ideas/thoughts/suggestions:- Eliminating the dependencies of the superclass on the subclasses is definitely a big improvement!
- Do you really need both an interface and an abstract class? Usually, when you use implementation inheritance, the abstract class takes the role of the interface.
- The DoubleComparator does not satisfy the Comparator contract - it's not transitive because of the epsilon. Suggest using Double.compare(x, y) whenever you need to compare two double values in a comparison method. Floating-point may arise when converting units, but not much you can do abo ut that.
- The spawn() method is a bit unnatural here because ordinarily you don't need to defensively copy immutable objects. In this case, it's to call a constructor in the superclass of an instance in the subclass. Interesting idea.
- Should the spawn() method return objects of type Radian/Degrees instead of Angle.
- You could add some simple methods like isAcuteAngle(), isRightAngle(), etc.
- Should isCongruent() consider 10 and 370 degrees as not congruent? This seems more natural, considering that isCoterminal() considers them as equal. What is the definition of isCongruent()?
- Instead of (presumably) made up units like zygos, use real ones like gradians (1/400 turn), points (1/32 turn), hours (1/24 turn), and seconds (1/1,296,000 turn). https://en.wikipedia.org/wiki/Angle#Units
- Perhaps add a method units() that returns the name of the units as a String, so that toString() can call that and get a text representation like "180.0 degrees".
- Since Angle stores the number of turns, you might encounter some floating-point issues, e.g., 72 degrees will lose some precision when it is stored as 1/5 turn. So, subclasses might benefit from using their own internal representation in native units - a fine exercise.
- Suggest isCongruentTo() and isCoterminalWith() instead of isCongruent() and isCoterminal().
Since the subclasses all have the same blueprint, an alternative design would be to have a single class that takes the units as argument and has a few cases in toString() and the constructor to handle the units, e.g., new Angle(30, Angle.DEGREES). This would be quite a bit simpler but less extensible. For example, if a client would need to modify Angle to use new units (e.g., gradians), they would need to modify Angle.java. So maybe this is the compelling usage - extensibility.
Best, Kevin
* END ACKNOWLEDGMENTS */