Question

I have the following code and architecture (in fact this is a very simplified version) consting of a abstract and a concrete class.

public abstract class AbstractProcessor {
    public void updateDataFromUrl(String url) {
        //Download url
        //Decrypt, and do a lot of stuff, 
        String data = "abc"; //Result from downloading

        String processed = processData(data);

        //Do a lot of other things with the transformed data
    }

    public abstract String processData(String data);
}


final class ConcreteProcessor extends AbstractProcessor {
    public void updateData(int year, int month, int day) {
        String url = String.format("http://%d.%d.%d", year, month, day);
        updateDataFromUrl(url);
    }

    @Override
    public String processData(String data) {
        //Process the data

        //---------------
        //PROBLEM:
        //----------------
        //Need access to year, month, day ....

        return null;
    }
}

The updateDataFromUrl method contains a lot of code (booth, before and after the processData call) which I want to reuse in several Processors, for this reason I put the code into a abstract class.

The problem is: I want to access the data which was provided to the newly added updateData method (here year, month, day). As the call flows through the abstract class which does not know of these parameters, this information gets lost. How can I modify this architecture to keep this information?

The following solutions came to my mind, all with obvious drawbacks:

  1. Provide the abstract method with the url and extract the parameters from there again. (Problem: What is there are parameters which I only need in the procecssData method and never in the url?)
  2. Split the updateDataFromUrl method into two two methods (the part before the processData call and the part afterwards). Now use these methods directly in the ConcreteProcessor. (Problem: The updateDataFromUrl method has a lot of context which I need both, before and after the processData call. How can I get this data transfered between the newly created methods?)
Was it helpful?

Solution 2

Only minor modifications lead to this solution (if I didn't miss some point (untested)).

You get the following benefits:

  • information passing is very straightforward (using instance variables)
  • you retain thread-safety
  • from an external (public) view, ConcreteProcessor can remain immutable

It would probably be best not to return a ConcreteProcessor from updateData but some immutable type that represents the transformed data.

public abstract class AbstractProcessor {
    public void updateDataFromUrl(String url) {
        //Download url
        //Decrypt, and do a lot of stuff, 
        String data = "abc"; //Result from downloading

        String processed = processData(data);

        //Do a lot of other things with the transformed data
    }

    public abstract String processData(String data);
}


final class ConcreteProcessor extends AbstractProcessor {
    public static ConcreteProcessor updateData(int year, int month, int day) {
            ConcreteProcessor p = new ConcreteProcessor(year, month, day);
            p.updateDataFromUrl(url);
            return p;
    }

    private /* instance vars for year, month, day, url, ... */

    private ConcreteProcessor(int year, int month, int day) {
            this.year = year;
            this.month = month;
            this.day = day;
            this.url = String.format("http://%d.%d.%d", year, month, day);
    }


    @Override
    public String processData(String data) {
        //Process the data

        //---------------
        // NO PROBLEM:
        //----------------
        //Easy to access to year, month, day using the instance vars

        return null;
    }
}

But the overall concept looks like a linear pipeline and therefore it would probably be best to make the pipeline more explicit. You will need some kind of state carrying but that shouldn't be a big problem using generics I think.

OTHER TIPS

Two ideas:

  1. Use instance variables in ConcreteProcessor to store year, month, day. Both methods can access the instance variable of the object. They are not accessible to the abstract class, though. Beware: the object is not thread-safe any longer. You must have multiple independent processors to process data concurrently.

  2. Reverse the dependency and use composition. A generic class Processor contains the common logic. When you invoke updateDataFromUrl you also pass an instance of a ProcessingStrategy that implements processData (indeed a kind of callback).

There are probably several variations of the ideas that are possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top