On Nov 5, 6:27 ¨Βν¬ Λαςμ φοΜαυδεςναξξ Όδοοδπα®®®ΐναιμιξατος®γονΎ wrote: > On Nov 4, 5:45 ¨Βν¬ Νιλε ΜοπλΌςεημο®®®ΐγαβμεοξε®ξετχςοτεΊ > > > For example, the typical Liskov Substitution example you see in Java has > > the case where you have a Rectangle class and a derived Square class. > > The Rectangle has an independent width and height. They have to be the > > same for the Square. > > One guiding principle when designing a class heirarchy is that the > class with fewer data members should be the superclass, and the class > with more data members should be the subclass. This sometimes leads to > cases which are counterintuitive with respect to the way we think of > things in real life. For example, Rectangle should be a subclass of > Square, not the other way around. This is because the Square class > only needs one dimension member variable, e.g. "width", and the > Rectangle subclass needs to add a second one, e.g. "height". The guiding principle is wrong. And it's an egregious error I keep seeing repeated. Lest a whole new generation of newbies follow this, lets name the real principle involved in the design of superclasses: abstraction based on common conceptual denominators, which in cs terms means essential common datamembers and essential common behavior gets aggregated to superclasses. This has NOTHING to do with # of datamembers. Repeating: Superclasses are based on common conceptual denominators (CCD)not on the number of data members. That in many-to-most cases there are fewer datamembers in the superclass is true, but not the guiding principle. And classically one uses the hierarchy to enforce certain constraints based on those CCDs. Also the simplicity of the example gives false security -- broadening the problem in question regards general closed shapes. For example. if I were designing this, the hierarchy in Ruby psuedocode, to capture the essential nature of the shapes, you have to encode that nature of a closed polygon which means closure, no self intercept for any enclosed area by arbitrary points. THEN you encode regular polygon behavior as sides of same length and then, if you need to, name squares, pentagons, hexagons as regular polygons and rectangles and similar as closed polygons. Now purists will scream but "square ARE rectangles!". Which is poor thinking. The correct statement is "Squares and Rectangles are four- sided closed shapes. Squares have equal sides, rectangles do not." As always, your *model* and its general power defines the flexibility of your application. Ruby pseudocode for clarity below. class ClosedPolygon @arrayPoints @orientation @anchor def initialize(arrPoints) if NoSelfIntercept==true raise NotAClosedPolygonException end if MoreThanOneIntercept==true raise NotAProperPolygonException end def draw end def size return @arrayPoints.length end def NoSelfIntercept end etc end class RegularPolygon < ClosedPolygon def initialize(arrPoints) if checkSidesEqualLength(arrPoints)!=true raise NotRegularPolygonException end @arrayPoints=arrpoints end def checkSidesEqualLength end end class Square < RegularPolygon def initialize(arrPoints) super.initialize(arrPoints) if self.size!=4 raise NotASquareException end end end class Rectangle < ClosedPolygon # See!!! CCD's properly differentiate # Square from Rectangle on Essential characteristics etc end which allows of course the proper definitions of things like class Pentagon < RegularPolygon etc end class IsoTriangle < ClosedPolygon etc end class EquiTriangle < RegularPolygon etc end which has little to do with datamembers (most are in the superclasses) and all to do with the common conceptual denominators of abstraction and where behavior is properly defined. My best to all.