📄 robustvisitor.java
字号:
package org.jutil.java.collections;import java.util.Vector;import java.util.List;import java.util.ListIterator;import java.util.Collection;import java.util.Iterator;import java.util.Enumeration;import java.util.ConcurrentModificationException;/** * <p>A robust visitor of collections. The code in visit is performed for each element * in the visited collection.</p> * <center><img src="doc-files/RobustVisitor.png"/></center> * * <p>Of course, sometimes exceptions can be thrown during a visit. The default * behaviour when an exception occurs, is to undo all changes that were made and * throw an exception to the caller of the method. This means that the actions * that were performed on elements visited before the element that caused the * exception, have to be undone. The RobustVisitor class adds support for * handling exceptions to the Visitor class.</p> * * <p>If an exception occurs while visiting the collection, the changes made to * the elements visited before the element that caused the exception, are * undone. To accomplish this, a method <code><a * href="RobustVisitor.html#unvisit(java.lang.Object, java.lang.Object)">void * unvisit(Object element, Object undoData)</a></code> is introduced, which * takes a visited element and data to undo the changes as arguments. The method * must undo the changes made to the given element. The undoData object is the * object that is returned by the <code><a * href="RobustVisitor.html#visit(java.lang.Object)">void visit(Object element) * throws Exception</a></code> method. If no undo data is necessary to undo the * changes, <code>null</code> can be returned. The changes are undone in the * opposite order as the changes were done. The changes of the visit that caused * the exception should be undone by the visit method itself, the other visits * are undone using the unvisit method. After all changes are undone, the * exception is propagated to the caller of the <code><a * href="RobustVisitor.html#applyTo(java.util.Collection)">applyTo</a></code> * method.</p> * * <p>The <code><a * href="RobustVisitor.html#visit(java.lang.Object)">visit</a></code> and * <code><a * href="RobustVisitor.html#applyTo(java.util.Collection)">applyTo</a></code> * methods throw <code>Exceptions</code> to keep the class as general as * possible. The <code>Exception</code> of the <code><a * href="RobustVisitor.html#visit(java.lang.Object)">visit</a></code> method can * be strengthened to one specific exception when overwriting the method, but * the <code>Exception</code> of the applyTo method can't because that method is * made final. That means that in the code you have to catch * <code>Exception</code>, which is a disadvantage of using a * <code>RobustVisitor</code>. Most methods we didn't think could be overwritten * in a useful way are made final. Even if we would allow to overwrite the * <code><a * href="RobustVisitor.html#applyTo(java.util.Collection)">applyTo</a></code> * method, the only way to strengthen the exception there is to insert a * try-catch block and call the super method, or copy the code from the * <codel>RobustVisitor</code: class, which both aren't any better. The only * elegant solution to the problem are generic classes, <a * href="http://developer.java.sun.com/developer/earlyAccess/adding_generics/">which * aren't supported yet in Java</a>.</p> * * <p><code>RobustVisitor</code> doesn't inherit from <code>Visitor</code> * because adding an exception to the throws clausule of the visit method would * violate LSP (Liskov Substitution Principle) and because the visit methods of * both classes have different return types. The last reason also prevents us * from doing the opposite, making <code>Visitor</code> inherit from * <code>RobustVistor</code> (which would also introduce a useless unvisit * method in <code>Visitor</code>).</p> * * <p><b><underline>Undoing changes the traditional way.</underline></b></p> * <pre><code> * Iterator iter = collection.iterator(); * Vector changed = new Vector(); * Vector undo = new Vector(); * try{ * while(iter.hasNext()) { * MyClass object = (MyClass) iter.next(); * // action code * changed.add(object); * undo.add(undoData); * } * } * catch(MyException exc) { * for(int i=changed.size(); i>= 0; i--) { * // undo action code; * } * throw exc; * } * </code></pre> * * <p><b><underline>Handling exceptions with the RobustVisitor.</underline></b></p> * <pre><code> * new RobustVisitor() { * public Object visit(Object element) throws MyException { * MyClass object = (MyClass) element; * // action code; * return undoData; * } * * public void unvisit(Object element, Object undoData) { * // undo action code; * } * }.applyTo(collection); * </code></pre> * * @path $Source: /cvsroot/org-jutil/jutil.org/src/org/jutil/java/collections/RobustVisitor.java,v $ * @version $Revision: 1.16 $ * @date $Date: 2002/07/21 17:56:59 $ * @state $State: Exp $ * @author Jan Dockx * @author Marko van Dooren * @release $Name: $ */public abstract class RobustVisitor implements CollectionOperator { /* The revision of this class */ public final static String CVS_REVISION ="$Revision: 1.16 $"; /** * The code to be applied to all elements of a collection. * If this method throws a Exception, unvisit will be called * on all elements that are already visited with the data they returned. * * @param element * The object the code should be applied to. */ /*@ @ public behavior @ @ pre isValidElement(element); @ @ post (* Data which enables to undo what visit has done @ in unvisit is returned. *); @ @ signals (Exception) @ (* Something went wrong while visiting <element>. *); @*/ public abstract Object visit(Object element) throws Exception; /** * This method will be called when the visit method has raised an * exception for some element which was visited after <element>. * The implementation should undo whatever visit did on <element>. * For that, <unvisitData> can be used. */ /*@ @ public behavior @ @ pre isValidElement(element); @ @ // unvisitData is the data returned by the visit method. @ pre unvisitData == visit(element); @ @ post (* the changes on <element> done by visit are undone *); @*/ public abstract void unvisit(Object element, Object unvisitData); /** * <p>Perform the visitation defined in <code>public void visit(Object)</code> * on <collection>. The contents of <collection> is not changed.</p> * <p>The collection is returned, so * that further operations can be applied to it inline.</p> * * @param collection * The collection to perform this visitation on. This can be null. */ /*@ @ public behavior @ @ pre (\forall Object o; collection.contains(o); isValidElement(o)); @ @ // The changes are applied to the given collection, @ // which is returned afterwards @ post \result == collection; @ // <code>public void visit(Object)</code> is called for all @ // elements of <collection>. @ post (* for all e in collection: visit(e) *); @ @ signals (ConcurrentModificationException) (* The collection was modified while visiting. *); @ signals (Exception) @ (* Something has gone wrong during the visit *); @*/ public final Collection applyTo(Collection collection) throws Exception, ConcurrentModificationException { if ((collection != null) && (! collection.isEmpty())) { List undoDataList = new Vector(collection.size()); try { Iterator iter = collection.iterator(); while (iter.hasNext()) { Object element = iter.next(); Object undoData = visit(element); undoDataList.add(new Entry(element, undoData)); } } catch(Exception exc) { // Only entries for elements that were succesfully visited are // in the list, so we have to call unvisit on all elements. ListIterator iter = undoDataList.listIterator(); // moving the iterator to the end. // thx Sun, for this wonderful interface while (iter.hasNext()) { iter.next(); } while (iter.hasPrevious()) { // The value is the undo data. Entry entry = (Entry) iter.previous(); unvisit(entry.getKey(),entry.getValue()); } throw exc; } } return collection; } /** * <p>Perform the visitation defined in <code>public void visit(Object)</code> * on <array>. The contents of <array> is not changed.</p> * <p>The array is returned, so that further operations * can be applied to it inline.</p> * * @param array * The array to perform this visitation on.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -