Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
198
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

The expressions are reusable for other purposes. You can add methods to the Expression to increase the functionality of the expressions. To add more flexibility, use the Visitor pattern, which lets you dynamically change the interpret method. (See “ Visitor ” on page 121.)

It might be difficult to create the abstract syntax tree—it isn’t defined by the Interpreter pattern. The Interpreter assumes the syntax tree has been created somewhere, somehow.

Pattern Variants

The original pattern as described in the GoF Design Patterns book uses an abstract class instead of an interface. As stated before, we recommend that you use interfaces wherever possible, unless a partial implementation should be supplied.

Related Patterns

Related patterns include the following:

Composite (page 157) – The structure for interpreted expressions is based on the composite pattern, using terminal expressions (leaf nodes) and nonterminal expressions (branch nodes).

Flyweight (page 183) – To reduce the number of redundant or similar objects, you can apply the Flyweight pattern to some of the Expressions.

Iterator (page 69) – Iterator is used to iterate through the abstract syntax tree and its nodes.

Visitor (page 121) – When a Visitor pattern is used, the Interpreter gains flexibility.

Example

Note:

For a full working example of this code example, with additional supporting classes and/or a RunPattern class, see “ Interpreter ” on page 381 of the “ Full Code Examples ” appendix.

The Expression hierarchy is at the heart of the Interpreter pattern. It defines the grammar that can be used to create and evaluate expressions. The Expression interface is the foundation for all expressions, and defines the interpret method that performs an evaluation.

Table 2-1 lists the interface and corresponding information.

Table 2-1. Purpose of the Expression interface and its implementers

Expression

Common interface for all expressions

ConstantExpression

Represents a constant value

VariableExpression

Represents a variable value, obtained by calling a method on some class

CompoundExpression

A pair of comparison expressions that evaluate to a boolean result

AndExpression

The logical “and” of two expressions

OrExpression

The logical “or” of two expressions

ComparisonExpression

A pair of expressions that evaluate to a boolean result

EqualsExpression

Performs an equals method comparison between the two expressions

ContainsExpression

Checks to see if the first String expression contains the second one

Example 2.8 Expression.java

1.public interface Expression {

2.void interpret(Context c);

3.}

48

Example 2.9 ConstantExpression.java

1.import java.lang.reflect.Method;

2.import java.lang.reflect.InvocationTargetException;

3.public class ConstantExpression implements Expression {

4.private Object value;

5.

6.public ConstantExpression(Object newValue) {

7.value = newValue;

8.}

9.

10.public void interpret(Context c) {

11.c.addVariable(this, value);

12.}

13.}

Example 2.10 VariableExpression.java

1.import java.lang.reflect.Method;

2.import java.lang.reflect.InvocationTargetException;

3.public class VariableExpression implements Expression {

4.private Object lookup;

5.private String methodName;

6.

7.public VariableExpression(Object newLookup, String newMethodName) {

8.lookup = newLookup;

9.methodName = newMethodName;

10.}

11.

12.public void interpret(Context c) {

13.try {

14.Object source = c.get(lookup);

15.if (source != null) {

16. Method method = source.getClass().getMethod(methodName, null);

17. Object result = method.invoke(source, null);

18. c.addVariable(this, result);

19.}

20.}

21.catch (NoSuchMethodException exc) {}

22.catch (IllegalAccessException exc) {}

23.catch (InvocationTargetException exc) {}

24.}

25.}

Example 2.11 CompoundExpression.java

1.public abstract class CompoundExpression implements Expression {

2.protected ComparisonExpression expressionA;

3.protected ComparisonExpression expressionB;

4.

5.public CompoundExpression(ComparisonExpression expressionA, ComparisonExpression

expressionB) {

6.this.expressionA = expressionA;

7.this.expressionB = expressionB;

8.}

9.}

Example 2.12 AndExpression.java

1.public class AndExpression extends CompoundExpression {

2.public AndExpression(ComparisonExpression expressionA, ComparisonExpression expressionB) {

3.super(expressionA, expressionB);

4.}

5.

6.public void interpret(Context c) {

7.expressionA.interpret(c);

8.expressionB.interpret(c);

9.Boolean result = new Boolean(((Boolean)c.get(expressionA)).booleanValue() &&

((Boolean)c.get(expressionB)).booleanValue());

10.c.addVariable(this, result);

11.}

12.}

Example 2.13 OrExpression.java

49

1.public class OrExpression extends CompoundExpression{

2.public OrExpression(ComparisonExpression expressionA, ComparisonExpression expressionB) {

3.super(expressionA, expressionB);

4.}

5.

6.public void interpret(Context c) {

7.expressionA.interpret(c);

8.expressionB.interpret(c);

9.Boolean result = new Boolean(((Boolean)c.get(expressionA)).booleanValue() ||

((Boolean)c.get(expressionB)).booleanValue());

10.c.addVariable(this, result);

11.}

12.}

Example 2.14 ComparisonExpression.java

1.public abstract class ComparisonExpression implements Expression{

2.protected Expression expressionA;

3.protected Expression expressionB;

4.

5.public ComparisonExpression(Expression expressionA, Expression expressionB){

6.this.expressionA = expressionA;

7.this.expressionB = expressionB;

8.}

9.}

Example 2.15 EqualsExpression.java

1.public class EqualsExpression extends ComparisonExpression{

2.public EqualsExpression(Expression expressionA, Expression expressionB){

3.super(expressionA, expressionB);

4.}

5.

6.public void interpret(Context c){

7.expressionA.interpret(c);

8.expressionB.interpret(c);

9.Boolean result = new Boolean(c.get(expressionA).equals(c.get(expressionB)));

10.c.addVariable(this, result);

11.}

12.}

Example 2.16 ContainsExpression.java

1.public class ContainsExpression extends ComparisonExpression{

2.public ContainsExpression(Expression expressionA, Expression expressionB){

3.super(expressionA, expressionB);

4.}

5.

6.public void interpret(Context c){

7.expressionA.interpret(c);

8.expressionB.interpret(c);

9.Object exprAResult = c.get(expressionA);

10.Object exprBResult = c.get(expressionB);

11.if ((exprAResult instanceof String) && (exprBResult instanceof String)){

12.

if (((String)exprAResult).indexOf((String)exprBResult) != -1){

13.

c.addVariable(this, Boolean.TRUE);

14.

return;

15.

}

16.}

17.c.addVariable(this, Boolean.FALSE);

18.return;

19.}

20.}

The Context class represents shared memory for expressions during evaluation. Context is a wrapper around a HashMap. In this example, the Expression objects provide the keys for the HashMap, and the results of calling the interpret method are stored as its values.

Example 2.17 Context.java

1.import java.util.HashMap;

2.public class Context{

3.private HashMap map = new HashMap();

5.public Object get(Object name) {

6.return map.get(name);

7.}

50

8.

9.public void addVariable(Object name, Object value) {

10.map.put(name, value);

11.}

12.}

With this series of expressions, it is possible to perform fairly sophisticated comparisons. ContactList holds a series of contacts in this example. It defines a method called getContactsMatchingExpression, which evaluates the Expression for every Contact and returns an ArrayList.

Example 2.18 ContactList.java

1.import java.io.Serializable;

2.import java.util.ArrayList;

3.import java.util.Iterator;

4.public class ContactList implements Serializable {

5.private ArrayList contacts = new ArrayList();

7. public ArrayList getContacts() { return contacts;

}

8.public Contact[] getContactsAsArray() {

return (Contact [])(contacts.toArray(new Contact [1]));

}

9.

10.public ArrayList getContactsMatchingExpression(Expression expr, Context ctx, Object key) {

11.ArrayList results = new ArrayList();

12.Iterator elements = contacts.iterator();

13.while (elements.hasNext()) {

14.Object currentElement = elements.next();

15.ctx.addVariable(key, currentElement);

16.expr.interpret(ctx);

17.Object interpretResult = ctx.get(expr);

18.if ((interpretResult != null) && (interpretResult.equals(Boolean.TRUE))) {

19.

20.

21.

22.

23.

24.

25.

26.

27.

28.

29.

30.

31.

32.

33.

34.

35.

36.

37.

38.

39. }

results.add(currentElement);

}

 

 

 

}

 

 

 

return results;

 

 

Y

}

 

 

 

 

 

L

public void setContacts(ArrayList newContacts) {

contacts = newContacts;

 

 

F

}

 

 

M

 

 

A

public void addContact(Contact element) {

 

E

 

if (!contacts.contains(element)) {

 

T

 

 

contacts.add(element);

 

 

}

}

public void removeContact(Contact element) { contacts.remove(element);

}

public String toString() { return contacts.toString();

}

With the Expression hierarchy and the ContactList, it is possible to perform database-like queries for the Contacts in a ContactList. For example, you could search for all those Contacts with a title containing the characters “Java” by doing the following:

Create a ConstantExpression with the string “Java”.

Create a VariableExpression with the target object and the string “getTitle”.

Create a ContainsExpression with the VariableExpression as the first argument and the

ConstantExpression as the second.

Pass the ContainsExpression into a ContactList object's getContactsMatchingExpression method.

TEAM FLY PRESENTS

51