5

Am sure that , everyone will be aware of the Transformers ( Optimus Prime , Megatron etc).

Am trying to represent that in the form of classes and interface. For now, am not considering the attributes. Am just taking some functionalities.

My Design is

interface Car{
 public void run();
 public void stop();
}

interface Robot{
 public void walk();
 public void fight();
}

class Transformer implements Car, Robot {
 // implementing all the methods
}

So the class Transformer says, it can perform both Car and Robot operations

During instantiation

Robot R = new Transformer(); // Now the transformer is in Robot format
Car C = new Transformer();  // Now the transformer is in Car format

My Question is ,here two objects that are getting created Robot R and Car C. So, this convey the Robot is getting created and Car is getting created . But what I want is The Car is Getting Transformed to A Robot and Vice Versa

How to implement this in design.

madhairsilence
  • 3,787
  • 2
  • 35
  • 76

7 Answers7

4

As I understand it, you want the Transformer class to have either Robot functionality OR Car functionality but not both at the same time.

To model that, I would favor Composition over Inheritance.

e.g.:

class Transformer {

private Car car;
private Robot robot;
private Class currentState = Car.class;

 public void fight() {
   if (currentState.equals(Robot.class)
      robot.fight();
   }

 public void drive() {
  if (currentState.equals(Car.class)
      car.drive();
  }

 public void transform() {
  if (currentState.equals(Car.class) 
      currentState = Robot.class;
  else
      currentState = Car.class;
}

To instantiate a new Transformer, you would need to define its Car-Form and its Robot-Form, e.g.:

new Transformer(new OptimusPrimeRobot(), new GiantTruck());

with the Constructor:

Transformer(Robot r, Car c) {
   this.robot = r;
   this.car = c;
}

with OptimusPrimeRobot implementing Robot and GiantTruck implementing Car.

If you want, you can even lazy initialize your contained classes. Define fields:

Class carClass;
Class robotClass;

and a Constructor:

Transformer(Class robotC, Class carC) {
   this.robotClass = robotC;
   this.carClass = carC;
}

Then make getter Methods for Robot and Car:

private Robot getRobot() {
  if(robot == null) {
     robot = robotClass.newInstance();
  }
  return robot;
}

and adjust your code, so it uses the Getters instead of the fields:

   getRobot().fight();

Now you just specify what Classes your Transformer consists of and their objects are only instantiated when needed.

Community
  • 1
  • 1
Jonas Eicher
  • 1,413
  • 12
  • 18
  • +1 for Hitting the bulls eye "Mutual Exclusion either Car or Robot" – madhairsilence Jul 19 '12 at 11:21
  • Can you tell how u will instantiate the transformer – madhairsilence Jul 19 '12 at 11:23
  • I've added an example. You would actually end up with 3 objects instead of one, but each would have it's distinct role and the composition makes sure their functionalities don't overlap. – Jonas Eicher Jul 19 '12 at 11:51
  • new OptimusPrimeRobot(), new GiantTruck()); Two objects here :( – madhairsilence Jul 19 '12 at 12:49
  • new Transformer(..) as well, as I said, 3 objects BUT a) Transformer is composed of the other 2 objects and each of those only carries half of the functionlity, making your resulting class carry no redundancy(like in your example with the 2 transformers) and b) Composition makes it easier to refactor. – Jonas Eicher Jul 19 '12 at 13:05
  • Transformer is composed of the other 2 objects - Brilliant!! But this just creates an illusion but eventually what happens it, two objects are getting created and they getting switched accordingly – madhairsilence Jul 19 '12 at 13:37
  • You could also do lazy initialization by making a constructor that accepts: new Transformer(OptimusPrimeRobot.class, GiantTruck.class); , so you can instantiate the objects with Reflection when you need them. – Jonas Eicher Jul 19 '12 at 16:16
1

You shouldnt have the Car transforming to a Robot. A Car is nothing but a Car and shouldnt know anything of Robots. But you can have a Transformer transform to Car or a Robot. I dont see why you need it but you could make something like this:

class Transformer implements Car, Robot {

  public Car transformToCar() {
     return (Car)this;
  }

  public Robot transformToRobot() {
    return (Robot) this;
  }
}

so then you could do:

Transformer optimus = new Transformer();
Car optimusCar = optimus.transformToCar();
//but this is the same as writing:
Car optimusCar = (Car) optimus;

As you can see the transformToXXX() methods really doesnt make sense as the Transformer always are both Car and Robot.

EDIT: You could of course move the transformToCar() definition into Robot and transformToRobot() definition into Car. Transformer class would then have to implement those methods.

activist
  • 121
  • 9
  • What about the implementation?? Am asking the Transformer to "Move".... If its a Car it should "Run"...If its a Robo , it should walk... But the method is same "Move" but the implementation is different – madhairsilence Jul 19 '12 at 11:35
1

Extend the Car interface with a transformation method:

interface TransformableCar extends Car {

    TransformableRobot asRobot();
}

Extend the Robot interface with a transformation method:

interface TransformableRobot extends Robot {

    TransformableCar asCar();
}

Create a class with two inner classes representing the two states:

public class Megatron {

    private MegatronCar car = new MegatronCar();
    private MegatronRobot robot = new MegatronRobot();

    public TransformableCar asCar() {
        return car;
    }

    public TransformableRobot asRobot() {
        return robot;
    }

    class MegatronCar implements TransformableCar {

        @Override
        public TransformableRobot asRobot() {
            return Megatron.this.asRobot();
        }

        // TODO: Implement Car methods
    }

    class MegatronRobot implements TransformableRobot {

        @Override
        public TransformableCar asCar() {
            return Megatron.this.asCar();
        }

        // TODO: Implement Robot methods
    }
}

Use it like this:

Megatron megatron = new Megatron();
TransformableCar car = megatron.asCar();
TransformableRobot robot = car.asRobot();
ᴇʟᴇvᴀтᴇ
  • 12,285
  • 4
  • 43
  • 66
  • You are not transforming :). You are creating new objects in asRobot and asCar methods. – titogeo Jul 19 '12 at 10:55
  • Well, it is transforming from the client's point of view, but I've edited to make it clearer. – ᴇʟᴇvᴀтᴇ Jul 19 '12 at 11:05
  • Hey!. This is what saying. A new Robot is getting created but it is not getting transformed to Robot – madhairsilence Jul 19 '12 at 11:15
  • From the client's point of view, it has a car, it calls asRobot() and now it has a robot. The car has effectively transformed into a robot. It's type-safe and if Robot and Car both define a stop() method (say) there can be different implementations for it without any worries about clashing, which you would have in your implementation. – ᴇʟᴇvᴀтᴇ Jul 19 '12 at 11:38
  • But after transforming i want to listen to my favorite channels that i had book marked before transforming to Robot. – titogeo Jul 19 '12 at 11:53
1

I'd use the strategy pattern Transformer would be a concrete class, which would delegate functionality to a RobotStrategy or CarStrategy. Both these would implement a TransformerStrategy

public interface TransformerStrategy{
    public void move();//implemented by both
    public void stop();//implemented by both
    public void fight();//implemented by only Robot, NO-OP for car
    //etc
}
qwerty
  • 3,801
  • 2
  • 28
  • 43
1

Decorator Pattern. Like in Collections class. Use static methods.

public static Robot transformCar(Car car){
        return (Robot)car;
    }
titogeo
  • 2,156
  • 2
  • 24
  • 41
0

I think you need to describe your use cases at bit more.

To me, there is little in common between the Car and the Robot. If it's currently a Car, I want it to call run and stop, if it's a Robot to call walk and fight. I don't want a design that allows me to call the wrong method when it's in an incorrect state and I can't imagine the behaviours I would want to call in both states. That almost sounds like a Transformer object composed of both a Car and Robot object, with a getter to return the current state. But maybe if you describe the use cases more something different would be suitable. Interesting question.

matt freake
  • 4,877
  • 4
  • 27
  • 56
0

Just got some shape here...

But the problem here is, the transformer WALKS explicitly and the CAR runs explicitly.Which says, they are two different objects. I want them, thats it!

public class TransformersClass{

    public TransformersClass() {

        Car transformer = new Transformer(); // Initially they are Cars
        Robot robot = (Robot) transformer; // Now transformed to Robot. No new objects are created

    }

}

class Transformer implements Robot, Car {


    @Override
    public void run() {
        // TODO Auto-generated method stub

    }

    @Override
    public void walk() {
        // TODO Auto-generated method stub

    }

    @Override
    public void attack() {
        // TODO Auto-generated method stub

    }

    @Override
    public void fire() {
        // TODO Auto-generated method stub

    }

}


interface Robot {
    public void walk();
    public void attack();
    public void fire();

}

interface Car {
    public void run();
}
madhairsilence
  • 3,787
  • 2
  • 35
  • 76