views:

108

answers:

4

I'm trying to come up with a good design for converting a set of different objects into a common object. Basically, I receive one (of many slightly different) complex object from system A, and must convert it into a simpler object for system B.

The objects I'm converting from all inherit from the same base class, so part of the conversion is always the same. But in every case, the conversion does involve something very specific to the type of the object I'm converting. It could be a RPC, an HTTP fetch, a database lookup, or something entirely different.

I'm looking at the Template method and the Strategy patterns. But neither seems like a perfect fit. The problem is that the method/strategy to use is tied to the type of object being converted and so isn't interchangeable.

This is a sketch of what I'm thinking about doing:

class FooConverter {
    Map<String, FooConverter> converters;
    Foo convert(Bar bar) {
        Foo foo = ...;  // Common part of the conversion.
        FooConverter c = converters.get(bar.getType(), foo);
        c.finishConversion(bar, foo);
        return foo;
    }
}

What annoys me is that FooConverter must define an additional conversion method that takes the partially converted object as a parameter. So I end up with a mix of a Strategy (since all the converters implement the same interface) and Template method (since the common part of the conversion is shared by all the converter). Is there a better way?

A: 

You could implement a subclass of the target type with a constructor for each of the given types you're converting from. From the constructors call the overloaded constructor of its parent type.

Something like:

public class ConvertedFoo extends Foo
{
    public ConvertedFoo(SuperTypeA a) {
        // Do some common stuff here.
    }

    public ConvertedFoo(SubtypeOfSuperTypeA a) {
        ConvertedFoo((SuperTypeA)a);
        // Do more specific stuff here.
    }
}

If the ConvertedFoo class gets too large, it can easily be split up for subtypes.

This would allow for maximum code re-use and would centralize of all your conversion code without the use of dynamic type-checking.

I don't think this is a named pattern. If anyone knows, I'd like to know its name.

Ben S
That looks good. But I can't use the class to determine the conversion I need, I really need to call `getType()` to determine the type of conversion needed.
albertb
Also, I'd rather not instantiate a new object for each conversion since I have pools of connections, etc. that I'd rather not make global.
albertb
Why do you need to call getType? Simply call the constructor with the object to convert it. Unless you're down-casting all your objects into a collection....
Ben S
In your example you're instantiating a new object for each conversion as well. How else would you convert an object? You need to create at least one new object: the result of the conversion.
Ben S
The connection pools don't have to be global, you could just pass that to the constructor as well.
Ben S
A: 

You are taking a bunch of "Convertable" objects, perhaps you could make "Foo" have Decorators for each "Convertable" base type, when you detect the "Convertable" type, you can add the appropriate Decorator to the "Foo"?

gnarf
+1  A: 

It sounds like you need to traverse a structure and be able to do something with each element in the structure. That 'something' varies by the type of the element, and you also want to be able to vary how that 'something' is implemented.

If that is the case, it sounds like a perfect fit for the Visitor pattern. I just recently used it myself in a scenario much like yours where I needed to convert one structure into another in a flexible manner.

Mark Seemann
+1 Visitor pattern sounds like the best fit here.
skaffman
The visitor pattern does sound like the way to go, thanks! Since I can't modify classes form system A, I'll need some kind of wrapper for Bar, but it shouldn't be too bad.
albertb
+1  A: 

There are at least two ways to do it:

  1. Use the template method. That is have a conversion method in super class (Bar) and implement it in subclasses (eg, MyBar, HttpBar etc). This is fine as long as the class knows how to convert itself. You can have a method toFoo() in Bar. Subclasses will call super.toFoo() and additionally do the stuff needed.
  2. The above method may not be always desirable since conceptually conversion is not the job of Bar. In this case you can use the Visitor pattern. You can have a parallel hierarchy of conversion classes. Each class can accept some particular type of Bar and do the conversion.