flowsnake
flowsnake

Reputation: 75

creating objects and polymorphism

I want to avoid using tagged classes and big if-else blocks or switch statement and use polymorphism with a class hierarchy instead, which I believe is better practice.

For example, something like the below, where the choice of executed method is dependent only one one field of an object of type Actor.

switch(actor.getTagField())
{
    case 1: actor.act1(); break;
    case 2: actor.act2(); break;
    [...]
}

would become

actor.act();

and the act method would be overridden in subclasses of Actor.

However, the most obvious way to decide at runtime which subclass to instantiate looks awfully similar to the original:

Actor newActor(int type)
{
    switch(type)
    {
        case 1: return new Actor1();
        case 2: return new Actor2();
        [...]
    }
}

so it seems like nothing has really been gained; the logic has just been moved.

What is a better way to do this? The only way I can come up with involved implementing a factory class for each subclass of Actor, but this seems rather cumbersome for such a simple problem.

Am I overthinking this? It just seems like there's no point making the original change if I just do pretty much the same thing elsewhere.

Upvotes: 7

Views: 2750

Answers (3)

Mike Valenty
Mike Valenty

Reputation: 8981

Switch statements aren't pure evil. It's really duplication that you're looking to eliminate with better design. Often times you'll find the same switch statement show up in different (far away) places in your code - not necessarily doing the same thing, but switching on the same data. By introducing polymorphism, you pull those switches together as different methods of the same object.

This does two things, first it reduces several switches to one switch inside of a factory and it pulls together spread out logic that probably depends on similar data. That data will turn into member variables in your objects.

It's also worth noting that you don't always end up with a switch statement under the hood of your factory. Maybe you could scan the classpath at startup and build a HashMap of types that implement an interface. For example, consider an implementation of a socket protocol like SMTP. You could have objects named HeloCommand, MailFromCommand, etc... and find the right object to handle the message by matching the socket command to the class name.

Upvotes: 3

ltiong_dbl
ltiong_dbl

Reputation: 3216

Question is "if" you need a factory. The factory is meant to manage the creation of instances an not so much the behavior of related instances.

Otherwise, you're just looking at basic inheritance. Something like..

class Actor{
  public void act(){
    System.out.println("I act..");
  }
}

class StuntActor extends Actor {
  public void act(){
    System.out.println("I do fancy stunts..");
  }
}

class VoiceActor extends Actor {
  public void act(){
    System.out.println("I make funny noises..");
  }
}

To Use, you can just instantiate the type of actor you need directly.

Actor fred = new Actor();
Actor tom = new VoiceActor();
Actor sally = new StuntActor();

fred.act();
tom.act();
sally.act();

Output:

I act..
I make funny noises..
I do fancy stunts..

EDIT:

If you need to centralize the creation of the Actors..aka vis a Factory, you will not be able to get away from some kind of switching logic--in which case..i'll typically use an enumeration for readability:

public class Actor{
  public enum Type{ REGULAR, VOICE, STUNT }

  public static Actor Create(Actor.Type type){
    switch(type) {
      case VOICE:
        return new VoiceActor();
      case STUNT:
        return new StuntActor();
      case REGULAR:
      default:
        return new Actor();
    }
  }

  public void act(){
    System.out.println("I act..");
  }
}

Usage:

Actor some_actor = Actor.Create(Actor.Type.VOICE);
some_actor.act();

Output:

I make funny noises..

Upvotes: 4

Paul Vargas
Paul Vargas

Reputation: 42010

I believe that you can do it with Abstract factory pattern...

This is a example:

abstract class Computer {
    public abstract Parts getRAM();
    public abstract Parts getProcessor();
    public abstract Parts getMonitor();
}

class Parts {
    public String specification;
    public Parts(String specification) {
        this.specification = specification;
    }
    public String getSpecification() {
        return specification;
    }
}

We have two class that extends Computer

class PC extends Computer {
    public Parts getRAM() {
        return new Parts("512 MB");
    }
    public Parts getProcessor() {
        return new Parts("Celeron");
    }
    public Parts getMonitor() {
        return new Parts("15 inches");
    }
}

class Workstation extends Computer {
    public Parts getRAM() {
        return new Parts("1 GB");
    }
    public Parts getProcessor() {
        return new Parts("Intel P 3");
    }
    public Parts getMonitor() {
        return new Parts("19 inches");
    }
}

And finally we have,

public class ComputerType {
    private Computer comp;
    public static void main(String[] args) {
        ComputerType type = new ComputerType();
        Computer computer = type.getComputer("Workstation");
        System.out.println("Monitor: "+computer.getMonitor().getSpecification());
        System.out.println("RAM: "+computer.getRAM().getSpecification());
        System.out.println("Processor: "+computer.getProcessor().getSpecification());
    }    

    public Computer getComputer(String computerType) {
        if (computerType.equals("PC"))
            comp = new PC();
        else if(computerType.equals("Workstation"))
            comp = new Workstation();
        return comp;
    }    
}

Upvotes: 2

Related Questions