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();
}
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.
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.
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;
}
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;
....
}