A froggy visitor
John Hofman (Talk | contribs) (Added UML diagrams for visitor pattern application and Lukas' suggested solution.) |
|||
(5 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
− | + | Homework excercise for us! | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
+ | This exercise was introduced during a discussion about this [[Frogs design]] example. The question was raised concerning the "exportXML()" method of the frog class: | ||
− | [[ | + | [[Image:Frog_export_exercise.gif]] |
+ | Is this method good, evil, or the lesser of two evils? | ||
− | [[image: | + | * This method contradicts the [[Model the real world]] maxim. A frog does not know about exporting itself and should not be able to. |
+ | |||
+ | * If the frog did not know how to export itself then another class would need internal access to achieve this. However, this will break the [[Encapsulation boundary]]. | ||
+ | |||
+ | Riel states [[Model the real world]] is often violated for keeping related data and behaviour in one place so the current exportXML may very well be the lesser of these two evils. | ||
+ | |||
+ | =Alternate Solutions= | ||
+ | |||
+ | A solution to this problem would involve | ||
+ | * IExporter -- an interface defining: | ||
+ | ** An export method taking a property name and a property value (overloaded to support int, string, etc differently). | ||
+ | ** BeginSubsection and EndSubsection methods to allow them to export, for instance, their legs. They can BeginSubsection("leg1"), then ask their first leg to export itself, then End(the)Subsection() | ||
+ | * Frog::Export(IExporter) -- a method exporting this frog to whatever format is passed in. | ||
+ | * XmlExporter -- A basic implementation of IExporter which exports to an XML file. Would probably take a filename in the constructor. | ||
+ | |||
+ | [[image:FroggyExporter.gif|frame|centre|'''Figure 1: A UML [[Class diagram|class diagram]] describing the suggested solution structure''']] | ||
+ | |||
+ | |||
+ | In this solution, the XmlExporter does not need to know about a frog, and the frog doesn't need to know Xml -- but it does need to be able to export itself in a relatively generic fashion. I don't think that's too much to ask of a frog. | ||
+ | |||
+ | Advantages of this approach are: that it is | ||
+ | * extensible for other types of exporters | ||
+ | * keeps coupling relatively loose | ||
+ | * the [[encapsulation boundary]] is preserved | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Another solution is to apply the [[visitor pattern]] to this design. | ||
+ | |||
+ | [[image:FroggyVisitor.gif|frame|centre|'''Figure 2: A UML [[Class diagram|class diagram]] describing the application of the visitor pattern to this problem''']] | ||
+ | |||
+ | Advantages | ||
+ | * A visitor of any type can be added (not just an exporter). | ||
+ | * The frog has no knowledge of the implementation of the exporter or any other visitor | ||
+ | |||
+ | Disadvantages | ||
+ | * Breaking [[encapsulation boundary|encapsulation]]: The frog's interface needs to be powerful enough to enable the exporter do its job. | ||
+ | * Adding another type of frog requires another operation in all the visitors. |
Latest revision as of 03:02, 18 July 2010
Homework excercise for us!
This exercise was introduced during a discussion about this Frogs design example. The question was raised concerning the "exportXML()" method of the frog class:
Is this method good, evil, or the lesser of two evils?
- This method contradicts the Model the real world maxim. A frog does not know about exporting itself and should not be able to.
- If the frog did not know how to export itself then another class would need internal access to achieve this. However, this will break the Encapsulation boundary.
Riel states Model the real world is often violated for keeping related data and behaviour in one place so the current exportXML may very well be the lesser of these two evils.
Alternate Solutions
A solution to this problem would involve
- IExporter -- an interface defining:
- An export method taking a property name and a property value (overloaded to support int, string, etc differently).
- BeginSubsection and EndSubsection methods to allow them to export, for instance, their legs. They can BeginSubsection("leg1"), then ask their first leg to export itself, then End(the)Subsection()
- Frog::Export(IExporter) -- a method exporting this frog to whatever format is passed in.
- XmlExporter -- A basic implementation of IExporter which exports to an XML file. Would probably take a filename in the constructor.
In this solution, the XmlExporter does not need to know about a frog, and the frog doesn't need to know Xml -- but it does need to be able to export itself in a relatively generic fashion. I don't think that's too much to ask of a frog.
Advantages of this approach are: that it is
- extensible for other types of exporters
- keeps coupling relatively loose
- the encapsulation boundary is preserved
Another solution is to apply the visitor pattern to this design.
Advantages
- A visitor of any type can be added (not just an exporter).
- The frog has no knowledge of the implementation of the exporter or any other visitor
Disadvantages
- Breaking encapsulation: The frog's interface needs to be powerful enough to enable the exporter do its job.
- Adding another type of frog requires another operation in all the visitors.