views:

93

answers:

2

I'll describe what I'm trying to do, and hopefully, somebody can tell me what design pattern this is or point out a better alternative.

I have a method doing a bunch of complicated stuff that involves an approximation. It is possible to compute the result without the approximation but this involves more work.

What I want to do is get out some comparisons related to the inner workings of the implementation. My idea is to pass in an object that would do this extra work and store the info about the comparisons.

I think I want to go from:

class Classifier(object):
    ...
    def classify(self, data):
        # Do some approximate stuff with the data and other
        # instance members.

to

class TruthComparer(object):
    def compute_and_store_stats(self, data, accessory_data):
        # Do the exact computation, compare to the approximation,
        # and store it.

    def get_comparison_stats(self):
        # Return detailed and aggregate information about the
        # differences between the truth and the approximation.

class Classifier(object):
    ...
    def classify(self, data, truth_comparer=None):
        # Do some approximate stuff with the data and other
        # instance members.
        # Optionally, do exact stuff with the data and other
        # instance members, storing info about differences
        # between the exact computation and the approximation
        # in the truth_comparer
        if truth_comparer is not None:
            truth_comparer.compute_and_store_stats(data,
                                                   [self._index, self._model],
                                                   intermediate_approximation)

The reason I don't want to do those comparisons inline within the classify method is that I don't think it fits the job of that method or object to do those comparisons.

So, what design pattern, if any, is this? Can you suggest an alternative?

A: 

My problem with your proposed change is that it doesn't seem right that the classifier requests the compute and store stats part. The classifier shouldn't really be concerned about that. Ideally, it shouldn't even know that the TruthComparer exists.

I'd suggest you really want two methods on Classifier: classify/classify_exact. Classify returns the approximate result; classify_exact returns the exact result. Instead of passing the TruthComparer as a parameter, give TruthComparer the two classifications and let it do its thing.

That way you reduce the number of objects your Classifier has to deal with (lower coupling), and I think makes what is going on clearer.

Winston Ewert
I did leave out some details. It's not the end result that I want to compare. I want to gather stats about some intermediate values used in the computation. The intermediate values that are generated by the approximate classifier use the data passed to the method _and_ some other instance members that aren't available to (because they aren't needed by) the exact classifier.
Sancho
In that case, I'd probably have my classify method return an object which holds the result of the classification + extra data. Then I'd pass that over to TruthComparer. (All in all, though, there is nothing really wrong with your design)
Winston Ewert
+1  A: 

You could use the Decorator Pattern. You define the Classifier interface and use a TruthComparerDecorator that inherits from Classifier. A TruthComparer, the decorator, takes a Classifier as input, computes the approximation with this classifier instance and then runs the compute_and_store_stats method. Using this pattern you a classifier does not need to know anything about a TruthComparer. In the end, a TruthComparer is a Classifier but does some more things. In Java this could look like:

public interface Classifier {
    void classify(Data data);
}

public abstract class TruthComparer implements Classifier {
    private Classifier classifier;
    public TruthComparerDecorator(Classifier classifier) {
        this.classifier = classifier;
    }
    public void classify(Data data) {
        classifier.classify(data);
        computeAndStoreStats(data);
    }
    public abstract void computeAndStoreStats(Data data);
}
kraftan