Thursday, January 26, 2012

Design a Business Expression with Interpreter Pattern

Introduction

In enterprise applications, we sometimes need to provide users a flexible way to configure the application. In this article, I will demonstrate how to design a general purpose business expression with the Interpreter pattern for this requirement.

Business Expression

An expression is a finite combination of symbols that is well-formed according to rules that depend on the context. The business expression we want to provide to the user has the following grammar definition:
Business Expression ::= ‘{‘ Operator ‘@’ Operand { ‘;’ … } ‘}’
Operator ::= ‘ADD’ | ‘SUB’ | ‘MUL’ | ‘DIV’
Operand ::= Business Expression | Data
Data ::= ‘1’ | ‘2’ …
There are several business expression examples:
{ADD@1;2}
This business expression represents we want to get the result of 1 + 2.
{SUB@3;2}
This business expression represents we want to get the result of 3 – 2.
{MUL@2;5}
This business expression represents we want to get the result of 2 * 5.
{DIV@4;2}
This business expression represents we want to get the result of 4 / 2.
{MUL@2;{DIV@{ADD:5;3};{SUB@5;1}}}
This is a more complicated business expression. It equals 2 * ((5 + 3) / (5 – 1)).

Applying the Interpreter Pattern

The definition of the Interpreter pattern is this: given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
Interpreter Pattern
From the definition of the Interpreter pattern, we can see a business expression is a perfect candidate to apply the Interpreter pattern. We can define each part of the business expression as a business expression class that is used to represent the business expression grammar and put them together as a business expression hierarchy.
Business Expression
In the business expression hierarchy, we have a BusinessExpression class similar to the AbstractExpression in the pattern, have BusinessDataExpression similar to the TerminalExpression in the pattern, and haveBusinessCompositeExpression together with all its subclasses similar to the NonterminalExpression in the pattern. Therefore, client routing can use the business expression to evaluate a given business expression string.
Where is the Context class?
The Interpreter pattern diagram has a context class. It’s not in my business expression diagram. The reason that I didn’t include a context class is because the purpose of the context class in the Interpreter pattern is to contain the input string and the result. Therefore, it’s not a must have class. Without the context class, I can just pass the input string into a business expression with an input parameter and get the result back with a return value.

How to use a business expression

To use a business expression, we need to follow these steps:
  1. Translate the business expression string into a business expression object tree.
  2. Evaluate the business expression object tree to get the result.
Translating into a business expression object tree
The business expression is given as a string, such as {ADD@1;2}. The way to translate this string into a business expression object tree is by traversing through each character in the string and translating any recognized term into the corresponding business expression object. The Parse static method on the BusinessExpression class is designed for translating a business expression string into a business expression object tree. It uses a process stack internally to store the intermediate results during the process. An intermediate result is represented with theProcessAtom class.
Process Atom
There are three types of ProcessAtom: Raw Data, Incomplete Business Expression, and Completed Business Expression.
Raw Data: It’s a single character in a business expression string. When the processor can’t determine how to convert a single character into a business expression, it will just store the character as raw data and wait for more information.
Incomplete Business Expression: It’s a business expression that has not been processed completely. A business expression starts with the symbol ‘{‘ and ends with ‘}’. Before the ending symbol is reached, the processor will just store an incomplete business expression into the process stack and wait for the ending symbol.
Completed Business Expression: It’s a business expression that has been fully processed. A completed business expression is generated by the processor after processing both ‘{‘ and ‘}’.
Evaluating business expression
After we have the business expression object tree, we can call the evaluate method of the root business expression object to get the result of business expression string. Each business expression object knows how to evaluate itself or get the result from containing business expression. The root business expression object consolidates the result together and returns back to the client.

Related Design Patterns

The business expression is a perfect candidate to apply the Interpreter pattern, however, the Interpreter pattern can’t fulfill the requirement by itself, there are other patterns employed.
Composite Pattern
The business expression object tree is built with the Composite pattern, so we can have nested business expressions in a business expression. By doing this, a more complicated business expression can be defined.
Factory Pattern
The Parse method has a fixed algorithm on how the business expression string gets parsed into a business expression object tree, but we might want to add a new business expression sometimes to support a new operation. According to the single responsibility principle, we should not let the parser method directly create the business expression object. Instead, we want the business expression object creation be done in a factory class. Therefore, we can just add a new business class and change BusinessExpressionFactory to return the new business expression object into the parser.
public class BusinessExpressionFactory
{
    public BusinessExpressionFactory()
    {
    }

    public BusinessExpression CreateBusinessExpression(string type)
    {
        BusinessExpression businessExpression = null;

        switch (type.ToLower())
        {
            case "add":
                businessExpression = new BusinessAdditionExpression();
                break;
            case "sub":
                businessExpression = new BusinessSubstractionExpression();
                break;
            case "mul":
                businessExpression = new BusinessMultiplicationExpression();
                break;
            case "div":
                businessExpression = new BusinessDivisionExpression();
                break;
        }

        return businessExpression;
    }
}

Summary

A business expression is a typical requirement for enterprise applications. By utilizing the Interpreter pattern, we can provide an elegant solution to fulfill it.

Using the Code

The code is developed in Visual Studio 2010. You can add your own business expression class into it to see the clarity and extensibility in the example from using Design Patterns.

No comments:

Post a Comment