Frogs design

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
(Go export yourself)
Line 32: Line 32:
  
 
[[image:frog.jpg]]
 
[[image:frog.jpg]]
 +
 +
Our discussion of this was quite polarized. Some thought the current "frog.exportXML()" arrangement was consistent with the [[Keep related data and behaviour together]] heuristic, seemed the most intuitive way of calling the method, and thus fine how it was.  Others expressed concern that having many classes with an "exportXML" method was not elegant, and would result in unnecessary repetition. Also, such methods violate the principles of [[One key abstraction]], [[Separation of concerns]], and the [[Single Responsibility Principle]].
 +
 +
Criticism is of little value unless a better solution can be proposed. Hence the latter camp suggested the Visitor pattern. Under their proposal, XML exporting methods would be grouped in an XMLVisitor class.  To export XML, the class would be used in this form:
 +
 +
frog.accept(xmlVisitor)
 +
 +
This is certainly a viable solution, and has the advantage of grouping all XML export methods within a single convenient class.
 +
 +
At this point we noted an intrinsic conflict between the design maxims. Separation of concerns seems to strongly contradict the idea that we must keep related data and behaviour together. We must then ask what we mean by "related", and what exactly defines a "concern".
 +
 +
My view was that XML-exporting methods for various objects are related in a technical sense (they work with the same format) but not in an object-oriented sense (they export totally different objects). The raison d'etre of object-oriented design is to group parts of a program on the basis of their real-world and logical relationships, rather than their technical relationships. Consequently, we ought to group a method that exports frogs in XML with frog-related program components, rather than XML-related program components. Thus the first solution seems more sensible to me.
 +
 +
Duplication of XML-exporting code can then be avoided by using an XMLExporter class that frog.exportXML and other exportXML methods can use behind the scenes within the implementation of that method.

Revision as of 06:13, 31 July 2008

An OO model of frogs. This beautiful design appeared in the 2004 427 exam.

Frogs.gif

Contents

Design notes

  • This design models the lifecycles of Frogs.
  • A Frog begins life as an Egg, grows into a Tadpole and then an AdultFrog.
  • A FrogBrain belongs to a Frog and manages its behaviour.
  • There is one Biologist, Igor, who sometimes moves Frogs around. Igor has been known to fry their legs in white wine.
  • Toads don’t have the same lifecycle as Frogs, but they look and act a lot like Frogs.
  • Toads eat AdultFrogs.

Broken heuristics

  • Avoid becomes - Frog phases of life are modeled by inheritance: Egg Tadpole, AdultFrog.
  • Beware type switches - the phase variable in Frog is based on the type of an object (Frog).
  • Beware value switches - the swim() method in Tadpole differs in behavior based on the value of an attribute (type).
  • Avoid no-op overrides ("Design by Contract") - the derived class Egg overrides the base class's hop() and swim() methods with methods which does nothing.
  • One key abstraction - the Move interface contains more than one key abstraction. It contains methods to move such as hop() and swim(), but it also contains a display() method which is a separate key abstraction.

"Feels Bad"

  • Toad is a subclass of AdultFrog.
  • FrogBrain contains an array of Egg.
Why do these things feel bad? --Wal

Go export yourself

Should a Frog be able to export itself?

Frog.jpg

Our discussion of this was quite polarized. Some thought the current "frog.exportXML()" arrangement was consistent with the Keep related data and behaviour together heuristic, seemed the most intuitive way of calling the method, and thus fine how it was. Others expressed concern that having many classes with an "exportXML" method was not elegant, and would result in unnecessary repetition. Also, such methods violate the principles of One key abstraction, Separation of concerns, and the Single Responsibility Principle.

Criticism is of little value unless a better solution can be proposed. Hence the latter camp suggested the Visitor pattern. Under their proposal, XML exporting methods would be grouped in an XMLVisitor class. To export XML, the class would be used in this form:

frog.accept(xmlVisitor)

This is certainly a viable solution, and has the advantage of grouping all XML export methods within a single convenient class.

At this point we noted an intrinsic conflict between the design maxims. Separation of concerns seems to strongly contradict the idea that we must keep related data and behaviour together. We must then ask what we mean by "related", and what exactly defines a "concern".

My view was that XML-exporting methods for various objects are related in a technical sense (they work with the same format) but not in an object-oriented sense (they export totally different objects). The raison d'etre of object-oriented design is to group parts of a program on the basis of their real-world and logical relationships, rather than their technical relationships. Consequently, we ought to group a method that exports frogs in XML with frog-related program components, rather than XML-related program components. Thus the first solution seems more sensible to me.

Duplication of XML-exporting code can then be avoided by using an XMLExporter class that frog.exportXML and other exportXML methods can use behind the scenes within the implementation of that method.

Personal tools