0

I'm designing a framework and I have composite objects that have sub objects that are executed asynchronously or synchronously. For the synchronous executing ones, there's usually a certain type of logic that has to run in the composite object after a certain sub item finished.

The issue is there's a number of sub items and for each sub item, there could be a different processing done after each sub item, and because i was aiming for simplicity, i had the synchronous items on a queue and composite item would just pop them one by one and run them.. Now what would be the cleanest way to track the sub items so that I can say something like "after sub item #2 is finished, take the data it returned and do xyz()"?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Tolga E
  • 12,188
  • 15
  • 49
  • 61
  • Can't the sub items do the necessary processing? – Jacob Raihle Jul 11 '12 at 16:00
  • @JacobRaihle actually they can't because the subobject might be used in two different composite objects where the post-processing is different – Tolga E Jul 11 '12 at 16:06
  • Are the sub objects supplied as arguments to the composite or instantiated inside the composite directly? – orangepips Jul 11 '12 at 16:53
  • Can you provide more details on the nature of the composite objects? Even better/sample names of the objects will give us the needed context to better answer your question. – tcarvin Jul 11 '12 at 17:23

3 Answers3

1

Command Pattern. This sounds like a CompositeCommand which maintains a list of Commands. Each Command has an execute() operation and CompositeCommand's execute operation iterates through the list of commands and calls each Command's execute. You can have the logic of doing xyz() after each iteration in CompositeCommand's execute() method.

You also mentioned each command can be processed differently which can be implemented by a Strategy.

user1168577
  • 1,863
  • 11
  • 14
1

Consider something like the Visitor Pattern if you have a limited amount of post-processing options.

The composite would implement one method for each type of post-processing that could be necessary, the sub items would implement a method which takes an instance of the composite and calls one of the post-processing methods, depending on which kind of sub item it is. Since you're already executeing the sub items, you could make them call the post processing methods at the end of that method instead.

An example, skipping the interface definitions:

class CompositeA implements Composite {
  public ? process() {
    for (Sub subItem : subItems) {
      subItem.execute();
      subItem.postProcess(this);
    }
  }

  public ? postProcessA(SubA subItem) {
    //do something with SubA
  }

  public ? postProcessB(SubB subItem) {
    //do something with SubB
  }
}

class CompositeB implements Composite {
  public ? process() {
    for (Sub subItem : subItems) {
      subItem.execute();
      subItem.postProcess(this);
    }
  }

  public ? postProcessA(SubA subItem) {
    //do something else with SubA
  }

  public ? postProcessB(SubB subItem) {
    //do something else with SubB
  }
}

class SubA implements Sub {
  public ? execute() {
    //doSomething
  }

  public ? postProcess(Composite composite) {
    comp.postProcessA(this);
  }
}

class SubB implements Sub {
  public ? execute() {
    //doSomething
  }

  public ? postProcess(Composite composite) {
    comp.postProcessB(this);
  }
}
Jacob Raihle
  • 3,720
  • 18
  • 34
  • Hey Jacob, thanks for the answer but unfortunately the postProcess will differ based on which composite task calls it.. So i'm not sure how to handle that as this way of doing it forces the sub item to do the same postProcessing regardless of which composite is calling it – Tolga E Jul 11 '12 at 16:28
  • Your different composites simply implement the postProcess method differently, I'll update my example for clarity. – Jacob Raihle Jul 11 '12 at 16:35
  • This actually looks like a very good way of handling the issue..So i guess the only downfall is we need to depend on the proper naming of the methods? (postProcessSubTaskName), which might lead to some errors later on. Still though i think this is a good way of handling it. Thanks! – Tolga E Jul 11 '12 at 18:03
  • Well, you could call any processing method you want as long as the `Composite` interface declares it - `SubA` can call `postProcessB` _if you want it to_, but I do recommend appropriate naming for your own sake :) – Jacob Raihle Jul 12 '12 at 08:01
0

I would suggest moving any dependent logic into an operation of its own.

abstract Operation
{
   abstract ? Execute(? arg);  // override in subclass to do work
}

abstract PostProcessOperation : Operation
{

   Operation _sourceOp;

   Operation(Operation sourceOp)
   {
      _sourceOp = sourceOp;
   }

   override ? Execute(? arg)
   {      
      ? sourceResult = _sourceOp.Execute(arg);
      return PostProcess(sourceResult);
   }   

   abstract ? PostProcess(? arg); // override in subclass to do work with results of the source op Execute

}

Then to, for example, add post-process console logging to an operation you could do this:

class ResultLogOp : PostProcessOperation
{
   override ? PostProcess(? arg)
   {
      Console.Writeline(arg.ToString());
   }
}

To further the example lets say you have a file delete operation and you want to post-process it by logging its success:

DeleteFileOp deleteFile = DeleteFileOp(fileToDelete);

ResultLogOp loggedDeleteFile = new ResultLogOp(deleteFile);

operations.Enque(loggedDeleteFile); 

Or if your usage is different perhaps your container class can wrap certain key operations as they are added based on their type:

void Add(Operation child)
{
   if (child is ImportantType)
   {
      _operations.Add(new ResultLogOp(child);  // add logging transparently on the fly
   }
}

The variations on this concept are endless.

tcarvin
  • 10,715
  • 3
  • 31
  • 52