Software Architecture – Handling Different Input Parameters in Java

Architecturecode-qualityjava

I am writing Java code to simulate a supply chain.
The supply chain can be simulated in either
an intermediate stocking or a cross-docking configuration.
So, I wrote two simulator objects IstockSimulator and XdockSimulator.
Since the two objects share certain behaviors
(e.g. making shipments, demand arriving),
I wrote an abstract simulator object AbstractSimulator
which is a parent class of the two simulator objects.

The abstract simulator object has a method runSimulation()
which takes an input parameter of class SimulationParameters.
Up till now, the simulation parameters only contains fields
that are common to both simulator objects,
such as randomSeed, simulationStartPeriod and simulationEndPeriod.
However, I now want to include fields that are specific to the type of simulation that is being run,
i.e. an IstockSimulationParameters class for an intermediate stocking simulation,
and a XdockSimulationParameters class for a cross-docking simulation.

My current idea is take the method runSimulation()
out of the AbstractSimulator class,
but to put a runSimulation(IstockSimulationParameters) method
in the IstockSimulator class,
and a runSimulation(XdockSimulationParameters) method
in the IstockSimulator class.
I am worried however, that this approach will lead to code duplication.

What should I do?

Edited

Currently, the AbstractSimulator class defines the runSimulation method
which calls other abstract methods
that are only defined by the concrete child classes.

public abstract class AbstractSimulator {
    public void runSimulation(SimulationParameters params) {
        int startPeriod = params.startPeriod;
        int endPeriod = params.endPeriod;
        for (int t = startPeriod; t < endPeriod; ++t) {
            submitReports(t);
            makeShipments(t);
            demandArrives(t);
        }
    }
    protected abstract void submitReports(int t);
    protected abstract void makeShipments(int t);
}

One of the differences between the IstockSimulator and the XdockSimulator
is that in an intermediate stocking configuration,
tier 3 facilities submit reports to tier 2 facilities,
while in a cross-docking configuration,
tier 3 facilities submit reports to tier 1 facilities.
Thus the IstockSimulator and the XdockSimulator
have their own implementations of the methods submitReports and makeShipments.

What worked for me

Thank you for your answers.
Inspired by your answers, and after sleeping it over,
I came up with my own answer based on refactoring.
See below.

Best Answer

I am worried however, that this approach will lead to code duplication.

yes, it might.

What should I do?

I suggest using generics. Like so

public abstract class AbstractSimulation<T extends SimulationParameters> {
    public void runSimulation(T parameters) {
        // common functionality
    }
}
public class SimulationParameters {
   // common parameters
}
public class StockSimulationParameter extends SimulationParameters {
   // specific parameters
}
public class StockSimulation extends AbstractSimulation<StockSimulationParameter> {
    @Override
    public void runSimulation(StockSimulationParameter parameters) {
        super.runSimulation(parameters); 
    }
}

// the same for XDockSimluation and XDocSimulationParameters
(... omitted for brevity ...) 

If you do this, StockSimulation.runSimulation() will only accept StockSimulationParameters instances, but not SimulationParameters:

StockSimulation stocksim = new StockSimulation();
// not OK
SimulationParamters simparamCommon = new SimulationParamters();
stocksim.runSimulation(simparamCommon);
// OK
StockSimulationParameter simparam = new StockSimulationParameter(); 
stocksim.runSimulation(simparam);
Related Topic