Ordered List


We have another story that we agreed to do: Ordered List. Take a look back at the seven steps (in the What s the Opposite of Simple? section) we used to have to do to implement a new set of tags, and let s see what we have to do now. We ll begin with a Customer Acceptance Test:

 *altO 
*output
<OL>
<LI></LI>
</OL>

Simple enough. We need a new menu item, which wants to look like this:

  insertOrderedList = new NotepadMenuItem (  
"Insert & OL",
new EventHandler(MenuInsertTags),
TextModel.Tags.OrderedList );
this.Menu = new MainMenu(new MenuItem[]
{fileMenu, insertPre, insertSection, insertUnorderedList,
insertOrderedList } );

We must add the new variable:

 private MenuItem insertPre; 
private MenuItem insertSection;
private MenuItem insertUnorderedList;
private MenuItem insertOrderedList;

With the previous implementation, we also had to add a new EventHandler method, add a new ModelAction variable, and initialize that variable to call a method inside the TextModel. We save all that effort, and perhaps more important, we don t have to remember to do it!

Our new code doesn t compile so far, with the message that TextModel.Tags doesn t include OrderedList. We build that and the support for it, as follows :

 class TextModel { 
private ArrayList lines;
private int selectionStart;
private static string[] newParagraph = { "<P></P>" };
private static string[] paragraphSkip = { "<P>" };
private static string[] newListItem = { "<LI></LI>" };
private static string[] listItemSkip = { "<LI>" };
private static string[] emptyLine = { "" };
private static string[] emptyLineSkip = { "" };
private static string[] newSection = {"<sect1><title></title>","</sect1>" };
private static string[] sectionSkip = { "<sect1><title>" };
private static string[] newUnorderedList = {"<UL>","<LI></LI>","</UL>"};
private static string[] unorderedListSkip = { "<UL>", "<LI>" };
private static string[] newOrderedList = {" < OL > "," < LI >< /LI > "," < /OL > "}; private static string[] orderedListSkip = { " < OL > ", " < LI > " };
private static string[] newPre = { "<pre></pre>" };
private static string[] preSkip = { "<pre>" };
public enum Tags {
Pre = 1,
Section = 2,
UnorderedList = 3,
ListItem = 4,
Paragraph = 5,
OrderedList = 6 }
private static string[] InsertStrings(Tags tag) {
if (tag == Tags.Pre) return newPre;
else if (tag == Tags.Section) return newSection;
else if (tag == Tags.UnorderedList) return newUnorderedList;
else if (tag == Tags.OrderedList) return newOrderedList;
else if (tag == Tags.ListItem) return newListItem;
else return newParagraph;
}
private static string[] SkipStrings(Tags tag) {
if (tag == Tags.Pre) return preSkip;
else if (tag == Tags.Section) return sectionSkip;
else if (tag == Tags.UnorderedList) return unorderedListSkip;
else if (tag == Tags.OrderedList) return orderedListSkip;
else if (tag == Tags.ListItem) return listItemSkip;
else return paragraphSkip;
}

This almost works, but not quite: the customer test fails at this line:

 private void ExecuteMenu(string accelerator) { 
MenuItem mi = form.MenuForAccelerator(accelerator);
mi.PerformClick();
}

We ve still forgotten one thing (but only one). We haven t picked up the new menu here:

 public MenuItem MenuForAccelerator(string accelerator) { 
if (accelerator == "&S") return insertSection;
if (accelerator == "&P") return insertPre;
if (accelerator == "&U") return insertUnorderedList;
if (accelerator == " & O") return insertOrderedList;
if (accelerator == "^O") return openFile;
if (accelerator == "^S") return saveFile;
return null;
}

With this change, the tests run perfectly . We have added OrderedList in a couple of minutes!

Things still are not perfect. I m most troubled by the fact that I had to remember to add that menu to the MenuForAccelerator() method, and I m a little troubled by the fact that I had to change five lines in the TextModel, even though they were all adjacent and pretty obvious. But for sure, things are much improved.

Think about it. This is really a rather large design change, yet it went largely without difficulty, and in very little time.

start sidebar
Lesson: Incremental Design and Development

Up until now, the incremental changes we ve been making have been simple, and most of them have been localized. The delegate changes we made in Chapter 22, The Delegate from Troy, were a bit larger, but even they were done in a short evening at the Michigan Union. This time the changes were far more significant, involving three significant classes, the XMLNotepad, the TextModel, and the tests. We implemented a new class, NotepadMenuItem, a subclass of MenuItem. We implemented an enumeration to encapsulate the idea of a command between Form and Model and between tests and Model. We refactored all those classes extensively and simplified them significantly.

Most important, we did it in small steps, never more than a moment or two from running tests. If we needed to ship the code, we could have done so at any moment, because the tests were always running, even if the code improvement wasn t finished yet.

Could we have done a better job earlier? Could we have seen that we should build this structure way back at the beginning? Well, perhaps you could have. I myself could not, new as I was to C# and to this application. And, frankly, if we had invested in this design, I fear that we would have spent a lot of time on it and still probably have gone down some wrong paths. As it is, we shipped running, tested software to our customer, and we kept it running, tested , and improving as we went. We have reached a better point ”though not a perfect one ”where it is now much easier and more reliable to add new tags.

end sidebar
 
start sidebar
Lesson: Open Questions

There are still some open questions, of course. There always will be. The ones that I see include these:

  • How can we be sure to find new accelerators more automatically? I m thinking in terms of storing all the menus in an array, instead of separate scalars, and looking them up in a simple loop. Then each new menu would automatically be found.

  • How can we simplify setting up and accessing the strings in the TextModel? At this writing, I m not sure. Perhaps we could do some kind of subscripting into tables of the insertion strings and the skip strings. Perhaps we could go to a more compact string notation like the one we envisioned earlier, with all the information in one string. Perhaps the commands would return these strings, or perhaps there is some new object waiting to be created.

  • How can we build user -defined tags? We have a story for user-defined tags. I m not sure whether we ll be called upon to implement it, but it is on the table. We will need a more sophisticated structure for looking up the values if we have to do this story.

  • Should we keep tag strings in a table? Right now, we have a nested if statement to find the tag strings. For a handful of items, this is probably fine. It does mean that we have to remember to update the list every time we add an item, which leads to a possible error. Using the tests in a disciplined way will find that error, but it is still a potential problem.

end sidebar
 



Extreme Programming Adventures in C#
Javaв„ў EE 5 Tutorial, The (3rd Edition)
ISBN: 735619492
EAN: 2147483647
Year: 2006
Pages: 291

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net