2

Imagine you have a list of Objects - like a list or array of objects representing users - and two processors:

  • one adds/delete/modify some user under certain circumstances
  • the other does the same thing by checking other conditions

circumstances/conditions are verified by taking advantage of other classes/services etc, which are injected when they are instantiated.

I want an architecture that allows me to add/remove processors with ease. I guess a decorator is quite good for this kind of job, but maybe a bit stiff when it comes at dynamically adding/removing processors at runtime.

Another idea is using something like a chain of responsibility, but letting each processor modify the list. I don't know if a kind of pattern like this exists or if it's a bad practice for some reason.

Let me know what you think :-)

  • Isn't your list an example of Repository? If yes, then why don't you inject that repository into each of processors? No need to build a chain of these, or decorating. – yegodm Mar 25 '18 at 17:07
  • What is the order of evaluation? Does the first processor checks the entire list in one pass, before the second processor is allowed to start doing the same? – rwong Mar 25 '18 at 18:57
1

Here’s what I would do:

Have an interface called Processor and let your two concrete classes implement it according to your two bullet points. Each class should handle any conditional logic itself and accordingly, any helper classes you need should be injected into the class that needs them.

Create a class called Processors (note the trailing s) and inject into it all objects that implement the Processor interface. In Spring, this can be easily done by injecting List<Processor>. In this class you will have just one method whose sole contents will be to iterate over the injected list and apply the processors. If order is important, instead of using automatic injection, create the bean explicitly in a Spring configuration class, passing it a list of processors in the correct order. Alternatively, you could use @Order annotation of your Processor beans and automatic injection, but this somewhat less clear for someone reading the code, in my opinion. If order is not important, just let automatic injection do all the work.

This solution has the following advantages: * Each processor is self-contained: it contains all logic needed to apply one kind of transformation, including any conditional logic. * Adding a new transformation is easy: just create a new bean that implements Processor (and if you go for the approach with manually injecting it into Processors, add it to the list in the constructor). * The class Processors does not need to be changed when you add a new processor.

  • I would go so far as to say Processors should also implement the Processor interface. – Hangman4358 Apr 1 '18 at 5:47
2

What strikes me about this is that you're talking about multiple processors and shared mutable state. This is rarely a good combination.

Rather, I see a way to select users. Why not use a filter?

A fairly readable method is to do it in steps.

List<User> users = originalUsers;
for (processor : processors) {
    users = users
        .stream()
        .filter(
            u -> processor.isPassable(u)
        )
        .collect( 
            Collectors.toList() 
        )
    ;
}

This of course sends any intermediate collections off to the garbage collector, which is fine if you're done with them.

You can certainly nest two streams here but it won't help readability and I'm reluctant to do that without performance tests that show it's worth it.

0

You would need to have classes that would implement a logic to determine whether you need to add, update or delete an object from the list. Let's call them the decision maker classes (DMCs).

Those classes should also contain classes that would perform each of those operations (add, update or delete). Let's call them Enforcer Classes (ECs)

Each DMC would need to have a reference to at least one EC. Now, you can either have a DMC have all three ECs somehow (three separate attributes, collection, etc.), or have just one and then dynamically assign the one that needs to be invoked. Which approach you choose depends on the specifics of your requirements.

Once this hierarchy is established, you need to have a container class that will decide which of the DMCs will be used.

In case all of them need to be invoked one after another, then the solution that @MichalKosmulski suggested is a good one.

If only one of them needs to be invoked, but you do not know which one, then Chain of Responsibility is what you need. Each DMC would represent a link in the chain. Each link would check whether it should be invoked, and if so, it would perfom the actions and stop there. If not, it would invoke the next link in the chain.

If only one of them needs to be invoked, and you know which one before runtime, then Strategy pattern is what you need, where the appropriate strategy would be instantiated on runtime. In that case, each DMC would be implemented as a strategy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.