This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Descriptor Method Pattern
Feed Title: David Buck - Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/buck-rss.xml
Feed Description: Smalltalk can do that
I'll leave the write code as an exercise for the reader.
There are a few problems with this. First, there are no data conversions being done. All the fields are being read as strings when certain fields should be converted to Integers, Booleans and Symbols.
Another problem, though, is that the file format is coded into the read method as well as the write method. This means that there are two different methods which must remain in sync. This violates DRY (Don't Repeat Yourself) and causes maintenance problems.
One way to tackle the problem is to build an object structure to describe the file format and get that structure to read and write the files.
For simple formats, this will work easily. If, however, the file format varies depending on the values of some fields, it gets more complicated. If, for example, the recordType is "AddNetworkElement", then the format of the rest of the line has information on the network element to add (possibly an IP address and a name). To have these conditions checked by an object structure, you would have to implement an Interpreter pattern which will really complicate the design.
The solution I use is one I call a "Descriptor Method". You write a method that describes the format but delegate all messages to a helper object stored in an instance variable. Here's what it looks like:
If the helper instance variable can contains a FileReader (which we'd have to write), then running the format method causes us to read a file using that format.
If the helper variable contains a FileWriter, then the format method causes us to write out a file using that format. We can also write helpers that report the file format without reading or writing anything. Another kind of helper could use code generation to create a DTO (Data Transfer Object) with the appropriate instance variables and accessor methods required by the format. Another kind of helper could verify that a file conforms to the format without reading its contents.
This technique can be used in more cases than just reading fixed file formats. It can be used to create SUnit testcases which include descriptions for a UI as well as the actual test code.
testSetAdd
self
| set |
name: 'Test Set Add';
description: 'Test the addition of elements to a set';
test: [
set := Set new.
set add: 3; add: 4; add: 7; add: 3.
self assert: set size = 3]
A GUI can plug in a TestCaseInformationHelper, run the method and collect the name and description of the test without running the test code. To run, plug in a TestCaseRunnerHelper. It will ignore the name and description and run the test code.
This technique works best in a language with lexical closures like Smalltalk. With lexical closures, the helper objects can choose whether or not to run the blocks. Without it, the descriptor methods have to ask the helpers whether or not to run the conditional code.