copyright © 2002, david a. hall writing and using java tm programming language-based predicates...
Post on 30-Jan-2016
220 views
TRANSCRIPT
copyright © 2002, David A. Hall
Writing and Using JavaTM Programming Language-Based
Predicates ('Java Predicates')
David Hall
copyright © 2002, David A. Hall
Functor
Functor: an Object that represents a function Evaluated as function: passed runtime arguments Functors can be passed as arguments Instantiated at runtime based on configuration Serialized or Persisted
copyright © 2002, David A. Hall
Functors vs. Method Objects
public void evaluate(Method m) { Object[] args = { arg1, arg2, etc }; try { Object val = m.invoke(args); } catch(IllegalAccessException x) { ... } catch(IllegalArgumentException x) { ... } catch(InvocationTargetException x) { ... }}
Number, types of arguments known in advance Compiler cannot check method's signature
copyright © 2002, David A. Hall
Functors vs. Method Objects
Functors can be nestedMethods are not dependent on each other
Functors are open for examinationMethods are opaque (no way to examine code)
Functors can be assembled at runtimeMethods must written prior to compilation
copyright © 2002, David A. Hall
Unary and Binary Functor
Unary Functorpublic interface UnaryFunctor { public Object fn(Object arg);}
BinaryFunctorpublic interface BinaryFunctor { public Object fn(Object arg1, Object arg2);}
Trinary, etc. are possible
copyright © 2002, David A. Hall
Predicate
Predicate: a Functor that returns a Boolean UnaryPredicate
public interface UnaryPredicate { public Boolean p(Object arg);}
BinaryPredicatepublic interface BinaryPredicate { public Boolean p(Object arg1, Object arg2) ;}
copyright © 2002, David A. Hall
Prolog
grandmother(G,S) :- parent(P,S), mother(G,P).mother(sarah,issac).parent(issac, jacob).
?- grandmother(sarah, jacob)yes?- grandmother(sarah, issac)no
copyright © 2002, David A. Hall
STL
Part of C++ Standard Library Contains a number of template based collections
classes and common algorithms Functors/Predicates used as arguments for many
of the algorithmscount_if(InputIterator first, InputIterator last, Predicate pred);
copyright © 2002, David A. Hall
STLArithmeticPlus(x, y)Minus(x, y)Multiplies(x, y)Divides(x, y)Modulus(x, y)Negate(x)
Comparisonmin(x, y)max(x, y)EqualTo(x, y)NotEqualTo(x, y)Less(x, y)LessEqual(x, y)Greater(x, y)GreaterEqual(x, y)
LogicalLogicalAnd(x, y)LogicalOr(x, y)LogicalNot(x, y)
ConstructionIdentity(x)ConstantUnary(x) ConstantBinary(x,y)Bind1st(x)Bind2nd(x)UnaryCompose(x)BinaryCompose(x)Project1st(x, y)Project2nd(x, y)
copyright © 2002, David A. Hall
jgl
Adaptation of STL in Java Originally created by ObjectSpace, inc Now owned by Recursion Software, Inc
http://www.recursionsw.com/
copyright © 2002, David A. Hall
Building Predicates
Primitives are easy to use, but of limited utilityPredicate andP = new LogicalAnd();Boolean flag = andP.p(Boolean.TRUE, Boolean.FALSE)
STL/JGL provide for assembly of compound expressions
copyright © 2002, David A. Hall
Bind1st & Bind2nd
Binders allow use of constant values with binary functors
Require BinaryFunctor, Constant at constructionUnaryFunctor discounter = new Bind1st(new Multiplies(), 1 - discountPct);UnaryFunctor taxer = new Bind1st(new Multiplies(), 1 + salesTaxRate);...salesPrice = discounter.fn(markedPrice);total = taxer.fn(salesPrice);
copyright © 2002, David A. Hall
Unary Compose
UnaryCompose allows result of one functor to be input to another
Requires two UnaryFunctors at constructionUnaryCompose netPrice = new UnaryCompose(taxer, discounter);...total = netPrice.fn(markedPrice);
copyright © 2002, David A. Hall
BinaryCompose
BinaryCompose is itself a UnaryFunctor BinaryCompose passes the results of two
UnaryFunctors as arguments to a BinaryFunctor Requires BinaryFunctor, two UnaryFunctors at
construction BinaryCompose cappedDiscount =
new BinaryCompose(new min(), discounter, new ConstantUnary(10.0));
copyright © 2002, David A. Hall
Miscellaneous
Constant returns value passed at construction Identity returns the runtime argument Project returns one of two runtime arguments
copyright © 2002, David A. Hall
Application Level Predicates
Primitives and assemblies provide support for built in reference types:
Arithmetic Functors require Number args Logical Functors require Boolean args Comparison Functors require Comparable args
No support for user/business level objects
copyright © 2002, David A. Hall
Custom Predicates
You can build customized functors for your business objects
public class GetStatusFn implements UnaryFunctor { public Object fn(Object arg) { PurchaseOrder po = (PurchaseOrder) arg; return po.getStatus(); }}
copyright © 2002, David A. Hall
GetPropertyFn
Alternatively, you can reflect using bean idiomspublic class GetPropertyFn implements UnaryFunctor { private String methName; public GetPropertyFn(String propName) { if (propName.startsWith("get")) methName = propName; else methName = "get" + propName; }...
copyright © 2002, David A. Hall
GetPropertyFn (cont.)
...public Object fn(Object arg) { try { Object[] parm = new Object[0]; Class[] types = new Class[0]; Class argclass = arg.getClass(); Method meth = argclass.getMethod(methName,types); return getMethod(arg).invoke(arg, parm); } catch (IllegalAccessException x) {...} catch (IllegalArgumentException x) {...} catch (InvocationTargetException x) {...} catch (NoSuchMethodException x) {...}}
copyright © 2002, David A. Hall
Business Rule Example
Business Rule exampleUnaryPredicate requiresApproval = new BinaryCompose(new GreaterThan(), new GetPropertyFn("Amount"), new ConstantUnary(500.00));
copyright © 2002, David A. Hall
SimpleCompare
public class SimpleCompare implements UnaryPredicate{ BinaryCompose bc; public SimpleCompare(BinaryPredicate comp, String propName, Object value) { fn = new BinaryCompose(comp, new GetPropertyFn(propName), new ConstantUnary(value); } public Boolean p(Object arg) { return (Boolean) bc.fn(arg); }}
copyright © 2002, David A. Hall
SimpleCompare
Same Business RuleUnaryPredicate requiresApproval = new SimpleCompare(new GreaterThan(), "Amount", 500.00);
copyright © 2002, David A. Hall
SimpleKey
Most SimpleCompare objects will use Equality comparisons, so create a special implementation
public class SimpleKey extends SimpleCompare { public SimpleKey(String propName, Object value){ super(new EqualTo(), propName,value); } }...UnaryPredicate pendingOrders = new SimpleKey("Status", "PENDING");
copyright © 2002, David A. Hall
Applications
Collections Swing: ListCellRenderer Dynamic Query & Query-By-Example EJB: BMP Finder methods Symbolic Set Manipulation
copyright © 2002, David A. Hall
Filtered Iterator
public class FilteredIterator implements Iterator { private Object next; private Iterator base; private UnaryPredicate pred; public FilteredIterator(Iterator iter, UnaryPredicate p) { base = iter; pred = p } ...
copyright © 2002, David A. Hall
Filtered Iterator (cont) ...
public boolean hasNext() { while (iter.hasNext() { Object obj = iter.next(); if (pred == null || pred.p(obj)) { next = obj; return true; } } return false; }...
copyright © 2002, David A. Hall
Filtered Iterator (cont)
... public Object next() { if (next != null) { Object val = next; next = null; return val; } throw new NoSuchElementException(); }}
copyright © 2002, David A. Hall
Collections & Algorithms
public Iterator findAll (Collecton coll, UnaryPredicate p) { return new FilteredIterator(coll.iterator(), p);}
public int countIf (Collection coll, UnaryPredicate p){ Iterator iter = new FilteredIterator(coll.iterator() , p); int ct = 0; while(iter.hasNext()) { iter.next(); ++ct; } return ct;}
copyright © 2002, David A. Hall
Swing Example
Swing provides many default models that work with built in primitives and/or collections of primitives.
You are expected to provide implementations that map your business objects within Swing defaults
By default, Swing hijacks toString() method
copyright © 2002, David A. Hall
ListCellRenderer
public class FunctorRenderer extends DefaultListCellRenderer{ private UnaryFunctor func; public FunctorRenderer(UnaryFunctor fn) { func = fn; } public Component getListCellRendererComponent( JList list, Object value, int index, boolean sel, boolean focus)
{ setText(func.fn(value).toString()); setBackground(sel ? Color.red : Color.white); setForeground(sel ? Color.white : Color.black); return this; }}
copyright © 2002, David A. Hall
ListCellRenderer Usage
JList list = new JList();UnaryFunctor fn = new GetPropertyFn("Id");list.setCellRenderer(new FunctorRenderer(fn)); getContentPane().add(list);
copyright © 2002, David A. Hall
Dynamic Query
Visitable and Visitor interfacespublic interface Visitable { public void accept(Visitor visitor);}public interface Visitor { public void visit(Visitable visitable);}
copyright © 2002, David A. Hall
Implementing Acyclic Visitor
Add Visitation support to SimpleKeypublic class SimpleKey extends SimpleCompare, implements Visitable{ ... public void accept(Visitor v) { if (v instanceof SimpleKey.Viz) ((SimpleKey.Viz)v).visit(this); } public interface Viz extends Visitor { public void visit(SimpleKey host); }}
copyright © 2002, David A. Hall
Translation Visitor
public class CloudscapeTranslator implements SimpleKey.Viz, ... { StringBuffer buf; public String translate(UnaryPredicate p) { buf = new StringBuffer(256); try { p.accept(this); } catch (Exception x) { x.printStackTrace(); } return buf.toString(); }...
copyright © 2002, David A. Hall
Translation Visitor
... public void visit(Visitable host) {} public void visit(SimpleKey host) { buf.append('"'); buf.append(host.getPropName()); buf.append("\" = "); host.getPredicate().accept(this); quote(host.getValue()); }...
copyright © 2002, David A. Hall
Translation Visitor
... private void quote(Object val) { if (val instanceof Number) { buf.append(val); } else if (val instanceof String) { buf.append("'"); buf.append(val); buf.append("'"); } // plus any other cases: Dates, Booleans, // Objects, etc }
copyright © 2002, David A. Hall
Translator Usage
private Collection selectIf(UnaryPredicate p) throws SQLException {
CloudscapeTranslator trans = new CloudscapeTranslator();
String selectStatement = "select \"poId\" from \"PurchaseOrderEJBTable\“” +” where " + trans.translate(p); PreparedStatement prepStmt = getDBConnection().prepareStatement(selectStatement);...
copyright © 2002, David A. Hall
Translator Usage (cont)
...ResultSet rs = prepStmt.executeQuery();ArrayList a = new ArrayList();while (rs.next()) { a.add(rs.getString(1));}prepStmt.close();return a;
}
copyright © 2002, David A. Hall
Predicates and Entity Beans
public interface OrderHome extends EJBHome { public Order create(String id, String userId, Date date, BigDecimal amount, String status) throws RemoteException, CreateException; public Order findByPrimaryKey(UnaryPredicate p) throws RemoteException, FinderException; public Collection findByPredicate(UnaryPredicate p) throws RemoteException, FinderException;
}
copyright © 2002, David A. Hall
Set Manipulation
Predicate implicitly defines a set (the set of all values for which the Predicate will return true)
Define set manipulation operations in terms of Predicates
Allows program to work with sets of values without having to instantiate them
copyright © 2002, David A. Hall
Set Manipulation
public class Predicates {
static public UnaryPredicate union(UnaryPredicate p1, UnaryPredicate p2) { return new BinaryCompose(new LogicalOr(), p1, p2);
/* thank you to the guy in the back row */}// intersection, set difference, etc
}
copyright © 2002, David A. Hall
References
Prolog http://mini.net/cetus/oo_prolog.html
STL http://www.yrl.co.uk/~phil/stl/
stl.htmlx#Algorithms_and_Functions http://www.byte.com/art/9510/sec12/art3.htm http://www.sgi.com/tech/stl/
JGL: Recursion Software, Inc http://www.recursionsw.com/
copyright © 2002, David A. Hall
References (cont)
Acyclic Visitor Patternhttp://www.objectmentor.com/resources/articles/acv.pdf
James O. Coplien. Advanced C++ Programming Styles and Idioms. Addison-Wesley, Reading, MA, 1992
Erich Gamma, et al. Design Patterns Elements of Reusable Object-Oriented Software. Addison-Wesley, Reading, MA, 1995
Kenneth P. Bogart. Discrete Mathematics. D. C. Heath and Company, Lexington, MA, 1988