Search code examples
design-patternscompositevisitor-patterneiffel

Visitor pattern and composite pattern


Im trying to develop a way to construct an arithmetic and logical expressions, and perform operations on them. For the structure I am using the composite pattern, and for the operations I am using the visitor pattern.

I am a little confused on the implementation of the concrete visitor class.

Here is how I currently do it:

My ADDITION class:

class
    ADDITION

inherit
    BINARY

create
    make

feature -- ctor
    make (left : EXPRESSION ; right : EXPRESSION)
        do
            left_expression := left
            right_expression := right
        end

feature -- deferred implementation
    evaluate : INTEGER
        do
            Result := left_expression.evaluate + right_expression.evaluate
        end

    to_string : STRING
        do
            create Result.make_empty
        end

    accept (v : VISITOR)
        do
            v.visit_addition (Current)
        end
end

Now for the visitor pattern, here is a concrete visitor that is supposed to evaluated the given expression (I also want a concrete visitor that does type checking, pretty printing, etc.).

class
    EVALUATE_VISITOR

inherit
    VISITOR

create
    make

feature -- attribs
    value : INTEGER
    value_bool : BOOLEAN

feature -- ctor
    make
        do

        end

feature

    visit_addition (expression : ADDITION)
        do
            value := expression.left_expression.evaluate +
                        expression.right_expression.evaluate
        end
end

My question is, doesnt having the evaluate method in each of my structures (ADDITION, SUBTRACTION, NEGATION, etc.) defeat the purpose of the visitor pattern, since all the evaluation should be done in the visitor class? How do I implement it in the visitor class then? I was thinking I could do something like:

visit_addition (expression : ADDITION)
    do
        value := expression.left_expression.accept(Current) +
                    expression.right_expression.accept(Current)
    end

but then I would have to have many accept methods in my structures, for arithmetic expressions it would have to return INTEGER, and for logical operations it would have to return BOOLEAN.


Solution

  • Actually the way to do this would be the following:

        visit_addition (expression: ADDITION)
            local
                l_left_value, l_right_value: INTEGER
            do
                expression.left_expression.accept (Current)
                l_left_value := last_value
    
                expression.right_expression.accept (Current)
                l_right_value := last_value
    
                last_value := l_left_value + l_right_value
            end
    

    This is in a visitor that computes additions of INTEGERs. The `last_value' attribute is defined in your visitor class.

    To answer your other question, in the ADDITION class you do not need `evaluate'.