0

I have an abstract class called "Operation" and this class has an abstract method called "Prepare".

public abstract class Operation {
    public abstract void prepare() throws Exception;
    public abstract void run() throws Exception;
    // other stuff here that's not abstract
    public void printHelloWorld() { 
         System.out.println("Hello World!");
    }

}

The only issue is that some things that are "Operation" ( some classes that extends Operation ) need arguments to prepare ( some need ints, some need String, some need more complex data types..so it's not always an int )

public class Teleportation extends Operation {
   @Override
   public void prepare(int capacityRequired ) throws Exception {
        // do stuff
   }
   @Override
   public void run() throws Exception {
   }
}

What OOP pattern do I use to achieve this and how do I set up this code ?

EDIT :

Ideally, I want to prepare and run operations like this :

for (Operation operation : operations ) {
  operation.prepare();
  operation.run(); 
}

Assuming I use this solution :

 public class Teleportation extends Operation {
       private int cReq;
       public void setCapacityRequired(int cReq) {
         this.cReq = cReq;
       }
       @Override
       public void prepare() throws Exception {
                // I can do the preparation stuff
                // since I have access to cReq here
       }
       @Override
       public void run() throws Exception {
       }
    }

Then - I wonder if it's possible to avoid this :

 for (Operation operation : operations ) {
      if (operation.getClass().isInstanceOf(Teleporation.class)) {
               ((Teleporation)operation).setCapacityRequired( 5 );
      }
      operation.prepare();
      operation.run(); 
    }
MadSeb
  • 7,958
  • 21
  • 80
  • 121

4 Answers4

2

The very first thing to do here is to override the abstract class operation and overload with your capacity.

public class Teleportation extends Operation {

    public void prepare() throws Exception {
        prepare(0);
    }

    public void prepare(int capacityRequired) throws Exception {
        //do stuff
    }
}

And remember the KISS and YAGNI statements, there is no need to use design patterns anywhere in your code, just where they makes things simpler.

RamonBoza
  • 8,898
  • 6
  • 36
  • 48
2

You either need to expand the abstract class to include two method signatures or change the signature to take a varargs int parameter:

public abstract class Operation {
    public abstract void prepare(int... args) throws Exception;
}
Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
2

I would recommend having an additional constructor where you can add the necessary data that the implementation requires and store it in fields for the class implementation.

For your example:

public class Teleportation extends Operation {
    private final int capacityRequired;
    public Teleportation(int capacityRequired) {
        this.capacityRequired = capacityRequired;
    }
    public void prepare() throws Exception {
    // do stuff using the capacityRequired field...
    }
}

This approach applies for more complex parameters as well.

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • This is the best approach if you want to take advantage of polymorphism as you can hand any subclass of Operation to an object and it will always know it can call prepare() without having to worry about parameters. After all, the constructor is where you prepare the object for use - you don't generally want to use a separate method. – Ian Fairman Oct 10 '13 at 15:33
  • @MadSeb I read your edit and this approach supports it as well. – Luiggi Mendoza Oct 10 '13 at 15:39
  • Yes, indeed, I would have answered the same, basically you are assembling the object dependencies via the constructor (prepare), and then, you call run(), but I would argue you don't need the prepare() method...the object is prepared, and it is better to put the object in consistent state using the constructor, and then to prevent future mutations. +1 from me. – Răzvan Petruescu Oct 10 '13 at 17:03
  • @RazvanPetruescu Agreed - you probably won't need a prepare() method. – Ian Fairman Oct 11 '13 at 14:50
1

You can use generic class for your operation class:

public abstract class Operation<T>
{
    private T operationModel;

    public Operation(T operationModel)
    {
        super();
        this.operationModel = operationModel;
    }

    public abstract void prepare() throws Exception;

    public abstract void run() throws Exception;

    public T getOperationModel()
    {
        return operationModel;
    }
}

Then for concrete classes, extend it with proper parameter-type (You can have a specific class for each operation):

public class TeleOperation extends Operation<TeleOperationModel>
{
    public TeleOperation(TeleOperationModel operationModel)
    {
        super(operationModel);
    }

    @Override
    public void prepare() throws Exception
    {
        TeleOperationModel teleOperationModel = getOperationModel();
        //...

    }

    @Override
    public void run() throws Exception
    {

    }
}

public class TeleOperationModel
{
    private int capacity;
    ....
}

and:

public class MicroOperation extends Operation<MicroOperationModel>
{
    public MicroOperation(MicroOperationModel operationModel)
    {
        super(operationModel);
    }

    @Override
    public void prepare() throws Exception
    {
        MicroOperationModel  microOperationModel = getOperationModel();
        //...
    }

    @Override
    public void run() throws Exception
    {

    }
}

public class MicroOperationModel
{
    private int x;
    private int y;
    private int z;
    ....
}
Arya
  • 2,809
  • 5
  • 34
  • 56
  • 1
    I see some issues here: 1) Some implementations won't need any parameter at all, so this will result in having to call `super(null)` in constructor of these classes. 2) There may be cases where you need more parameters from different types, so even having a `List` will result in having very specific class implementations constructors and/or prepare/run implementations. – Luiggi Mendoza Oct 10 '13 at 16:21