This is some more comments on Stefan's v0.11 of the FindReplaceBean, and a draft of a specification for the FindBean,
Ok, so I think the bean should be broken down into more, smaller beans. What you've prototyped, Stefan, is probably closest to a FindBean (or FindOnlyBean). This itself would be a useful component, we should make on of these too. Then the FindBean could be a service used by the FindReplaceBean.
I've only browsed the code very quickly, the main comment is about inheritance and Interfaces. There's no need to extend java.beans.Bean - you don't need to do this make a Bean, it happens automagically just from the get/set methods, and the fact it's Serializable.
However it's probably a good idea to eventually include a FindBeanInfo/FindReplaceBeanInfo (extends java.beans.SimpleBeanInfo) class, but this can wait, that's more of a tweaking exercise (for example, the JFC only just included this for all classes in v0.51).
So let's try a more abstract architecture, based on interfaces.
[I'm going to use the letter I as a prefix for Java Interfaces, reminiscent of COM I know but I'm getting used to the idea.]
// package org.jos.apps.FindBean ?? // spec v0.1, 9 Nov 97. SimonSpringall public class FindOptions { // methods to set/get debug, ignoreCase, searchText, wholeWords, wildcards, searchDirection // and the input (Reader) can be specified here. boolean getDebug(); void setDebug(boolean); boolean getIgnoreCase(); void setIgnoreCase(boolean); boolean getWholeWords() void setWholeWords(boolean) boolean getWildcards() void setWildcardss(boolean) SearchDirection getSearchDirection() void setSearchDirection(SearchDirection); String getSearchText() void setSearchText(String) Reader getReader(); void setReader(Reader); } // This belongs with the FindReplaceBean, not // the find Bean... public class FindReplaceOptions extends FindOptions { // all of FindOptions, plus, methods to set/get replaceText, and output (Writer) can be specified here. // Question : the FindOptions includes a wildcards options, should we // also support position-based substitution like awk (or is it perl?). Not for now.. String getReplaceText() void setReplaceText(String); Writer getWriter(); void setWriter(Writer); } public Interface IFindBean { void setOptions(FindOptions); FindOptions getOptions(void); java.util.Iterator /* Java 1.2 class */ getIterator(); // This will essentially start the search off. If no options have been set, this // with either just return null or throw some exception // Question: What is our error-reporting policy? Are exceptions good? // If we don't want to use Java 1.2 (although I much prefer Interator to Enumeration) // we can have the following. We _could_ do both anyway. java.util.Enumeration getEnumeration(); // This will also start off the search. See getIterator(). } public class FindBeanResult { // This is one of the results, accessed via the Iterator or Enumeration // returned from the IFindBean... // Infact, this could be an interface too. // for example : // // java.util.Iterator iter = mybean.iterator // while(iter.hasNext()) { // FindBeanResult result = (FindBeanResult)iter.next(); // ... // } int getOffset(); // This returns the offset into the found buffer String getMatchedString(); // If wildcards, or case-insensitve, we may need this to // determine what was actually found. } // end spec...
There's probably more to do, and some holes to fill in.
Any FindBean implementation will look like this:
class JOSFindBeanByStefan implements IFindBean, Serializable { void setOptions(FindOptions); FindOptions getOptions(void); java.util.Iterator getIterator(); // OR: java.util.Enumeration getEnumeration(); } or: class JOSFindBeanBySimon implements IFindBean, Serializable { void setOptions(FindOptions); FindOptions getOptions(void); java.util.Iterator getIterator(); // OR: java.util.Enumeration getEnumeration(); }
We can then implement our JOSFindBeans independantly, but the client of the FindBean (the GUI, or the shell, or the FindReplaceBean) just uses the interface IFindBean and the returned result class FindBeanResult. Then the implementations can be swapped without any code changes at all, in fact this could be dynamically, and/or by the end user. This is one of the beauties of interfaces.
-- Created 9 Nov 97 SimonSpringall
The FindOptions should maybe made an interface or abstract class. Furthermore it should not worry about about e.g. wildcards. The current FindOptions give too much hint on the implementation - it is not generic enough. IMHO the only valid options for find are ignore case, non-greedy match (in a simple FindBean useless, but in a RegularExpression based one very important), and search directions. This should be enough for a generic FindOptions class. Stuff like Wildcards should be left to the differnet implementations of the FindBean interface. There could e.g. be a SimpleFindBean , a SimpleRegexpFindBean and a ComplexRegexpFindBean or beans covering... well - who knows? I also agree that the FindBean should be splitted in several interfaces/abstract classes. What I want to achieve is the ability to control different find algorithms with one interface. The real FindBean's could be constructed by a factory. -- MarkusPeter
... TextBean mytext = new TextBean(); mytext.add("hello jos, this is a test. Please ignore"); // Search "test", forward, ignore case FindIteratorOptions fio = new TextFindIteratorOptions; fio.add("patter", "test"); fio.add("direction", "forward"); fio.add("ignore case", "true"); FindIterator fi = new TextFindIterator(mytext, fio); while (fi.hasMoreHits()) { System.out.println(mytext.wordAt(fi.nextHitPos())); } ... Directoy d = System.getFileDir("/"); // Search "test", case ignore, max recurse level FindIteratorOption fio = new DirectoryFindIteratorOptions; fio.add("case ignore", "true"); fio.add("pattern", "test"); fio.add("recurse", "2"); FindIterator fi = new DirectoryFindIterator(d, fio); while (fi.hasMoreHits()) { ... } ... // New (12.11.97): Some _internals_ class DirectoryFindIterator extends DirectoryIterator implements FindIterator { ... protected DirectoryFindIteratorOptions fio; protected boolean match(String m) { return(Regex.match(m, fio.get("pattern"))); } protected String nextHit() { String m = null; // Compare filenames against pattern while(!super.hasMoreHits() && !match(m) m = super.nextHit(); } if (m != null) { return(m); // match found } else _hasMoreHits = false; // no match return(null); } } ... }PhilippMeier
Nice use/test case example! This is really the kinda stuff we need in addition to the interface.
Also have a look at the strategy pattern in the GOF Book.