Search code examples
oopdesign-patternscompositemulti-levelchain-of-responsibility

Design Pattern for executing requests on different "output levels"


I am parsing a string like:

\read(customer) hello world


~> \method(arg, arg, ...)

into a composite data structure that persists of 1 to n arguments, which are requestLeaf objects, which arguments can be a requestLeaf object (if it's just plain text, that should be returned like above ("hello world")) or another requestComposite object (if there is some computation going on(like read->customer) until it's just plain text again.

requestComposite Object
(
  [requests:protected] => Array
      (
          [0] => commandRequest Object
              (
                  [methodName:protected] => read
                  [arguments:protected] => Array
                      (
                        [0] => commandRequest Object
                          (
                            [methodName:protected] => text
                            [arguments:protected] => customer
                          )
                      )
              )
          [1] => commandRequest Object
              (
                  [methodName:protected] => text
                  [arguments:protected] =>  hello world
              )
      )
)

What I want to achieve is to loop through the whole composite so that it renders some kind of document.

The arguments or leafs of the very first composite are representing the root or Level 0 for printing to the document.
I want to use a Library for this. This library can handle printing text, images, etc. but cannot evaluate anything!

Everything > Level 0 should be computed in another library.
This library can read member values, do some math, etc. and return its final value (exclusively strings) to the root to be printed out.
Everything else is printed explicit via e.g. \img() or \text()

There may be a

\read(x)

token to lookup a member value X,
whichs value should be printed implicit, (without wrapping it into another \text())!

there may be a \list() token to loop its arguments through a specified member list like:

\list(\read(x)))

X could be another Y

\list(\read(\read(y))).

In other words: I cannot know how deep the structure will be.

Happens that I'm fairly new to Design Patterns and OO in particular.
I am fiddling around with the Chain of Responsibility Pattern for "executing" right now, where the rendering/output library and the computation library are building the handler chain.
But I'm somewhat curious about if CoR really fullfills my needs:

How would you solve a problem like this?

EDIT: MY APPROACH AS FOR NOW

  1. to iterate through the composites.
    passing along a Mediator Object
    which contains the output library and the computation library.

  2. if current leaf is text
    check if current is the root
    if NO visit the computation library to evaluate the actual value and pass it to whom it may concern (e.g. \read(), \varput(), ...)
    if YES visit the output library to print it out

What comes to my mind is that I have to implement every requestMethod in both libraries to achieve the automatic root printing. i.e.
\read() in output should print text to the document,
\read() in the computation library should lookup a member value.

Am I overcomplicating things here?


Solution

  • continuing from comments, and assuming that you have built your composite tree from your input, what do you need that can not be done like this:

    import java.util.ArrayList;
    import java.util.List;
    interface Component {
        void add(Component component);
        List<Component> children();
    }
    class Composite implements Component {
        @Override public void add(Component component) {
            children.add(component);
        }
        @Override public List<Component> children() {
            return children;
        }
        List<Component> children=new ArrayList<>();
    }
    class Leaf implements Component {
        @Override public void add(Component component) {
            throw new UnsupportedOperationException();
        }
        @Override public List<Component> children() {
            return null;
        }
    }
    public class So34886186 {
        static String indent(int n) {
            String s="";
            for(int i=0;i<n;i++)
                s+=" ";
            return s;
        }
        static void print(Component root,Component component,int indent) {
            if(component instanceof Leaf)
                if(component.equals(root))
                    System.out.println(indent(indent)+"    root: leaf: "+component);
                else System.out.println(indent(indent)+"not root: leaf: "+component);
            else {
                if(component.equals(root)) {
                    System.out.println(indent(indent)+"    root: composite: "+component+": (");
                    for(Component component2:((Composite)component).children)
                        print(root,component2,indent+4);
                    System.out.println(indent(indent)+")");
                } else {
                    System.out.println(indent(indent)+"not root: composite: "+component+": (");
                    for(Component component2:((Composite)component).children)
                        print(root,component2,indent+4);
                    System.out.println(indent(indent)+")");
                }
            }
        }
        public static void main(String[] args) {
            Component root=new Composite();
            root.add(new Leaf());
            Component one=new Composite();
            root.add(one);
            one.add(new Leaf());
            Component two=new Composite();
            root.add(two);
            print(root,root,0);
        }
    }