views:

124

answers:

3

Hello Folks

I have a class ImageA, and a class ImageB. The both classes represents an image in my app, but each one in a different way. Even being different, their constructors are equal, and both have the method compare.

So, what I done was creating a class Image, and ImageA and ImageB are subClasses of Image.

public abstract class Image {
    protected String path;

    public Image(String path){
        this.path = path;
    }

    public abstract double compare(Image i2);
}


public class ImageA extends Image{...} 

public class ImageB extends Image{...}

But what I need is to test each implementation of image (ImageA and ImageB, in this case), to see the best one.

Is there a way to do this, changing my code at minimum? Suppose the objects used are from ImageA class, and I want to test now imageB class;

Obs.:

  • If all imageA objects of my app are setted by the type (ImageA i = new ImageA()), I'd have to change manually all in the code.

  • But even if I use the superType and cast it (Image i = (ImageA)new Image()), I'll have the same problem, to change the casts.

  • My question is different from this one: http://stackoverflow.com/questions/1456629/refactoring-abstract-java-class-with-many-child-classes . In my case, the attributes inside the child classes are different, and I keep the attributes common to these classes in the Image class.

+3  A: 

You could create a factory and pass an instance of your factory into the test class, using:

Image img = factory.newInstance(args);

throughout your test code. The factory determines which of the types ImageA or ImageB is used. An alternative would be to have a abstract Image newInstance(args) in your Image class and implement it in your subclasses. You would inject a first image instance into your test classes in that case.

Both methods rely on the fact that your args are the same between both types of images, you might need to pass in a superset to fulfill both constructors.

rsp
@rsp, your solution worked fine to me.
marionmaiden
+3  A: 

If this is an option (maybe I didn't get the question), you should use a factory method pattern to get the proper concrete class. The pizza sample is self explaining:

abstract class Pizza {
    public abstract int getPrice(); // count the cents
}

class HamAndMushroomPizza extends Pizza {
    public int getPrice() {
        return 850;
    }
}

class DeluxePizza extends Pizza {
    public int getPrice() {
        return 1050;
    }
}

class HawaiianPizza extends Pizza {
    public int getPrice() {
        return 1150;
    }
}

class PizzaFactory {
    public enum PizzaType {
        HamMushroom,
        Deluxe,
        Hawaiian
    }

    public static Pizza createPizza(PizzaType pizzaType) {
        switch (pizzaType) {
            case HamMushroom:
                return new HamAndMushroomPizza();
            case Deluxe:
                return new DeluxePizza();
            case Hawaiian:
                return new HawaiianPizza();
        }
        throw new IllegalArgumentException("The pizza type " + pizzaType + " is not recognized.");
    }
}

class PizzaLover {
    /*
     * Create all available pizzas and print their prices
     */
    public static void main (String args[]) {
        for (PizzaFactory.PizzaType pizzaType : PizzaFactory.PizzaType.values()) {
            System.out.println("Price of " + pizzaType + " is " + PizzaFactory.createPizza(pizzaType).getPrice());
        }
    }
}

Output:
Price of HamMushroom is 850
Price of Deluxe is 1050
Price of Hawaiian is 1150
Pascal Thivent
+1  A: 
sateesh