Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 996
flowsnake Avatar asked Apr 28 '12 22:04

flowsnake


2 Answers

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..
like image 69
ltiong_sh Avatar answered Sep 19 '22 02:09

ltiong_sh


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.

like image 31
Mike Valenty Avatar answered Sep 19 '22 02:09

Mike Valenty