I am writing an application for different geometrical types of fuel tanks.
I have a design problem that only at runtime I will receive the exact type of tank from the end user; and I don't know how to create/handle a dynamic object on the server side.
For example, a tank can have 3 geometrical types of head: conical, dished, and flat. Each type of head needs to be validated differently.
I have created a parent class named Head
that has all common parameters to all geometrical types of head (diameter, thickness etc.). Each child class (Conical
, Dished
and Flat
) extends Head
and has its own instance variables.
The end user will choose, for example, a tank with conical heads and input all the required parameters and send it to the server for validation.
At this stage I am stuck. I don't know how to handle the dynamic data. I got a suggestion to use Factory design pattern; but because every class has different variables, I don't think that is the right direction.
code without constructor and get/set methods
public class Head {
private float headThickness=0;
private float headThicknessTolerance=0;
private ShapeOfHead headShape;
private float knuckleRadius=0;
private int numberOfHeadPieces=4;
private HeadSide headSide;
private Figure8_1WeldingDetails headLongitudinalWeld;
private Figure9_1WeldingDetails headCircumferentialWeld;
private Bracing headBracing;
}
public class DishedHead extends Head {
private float dishedHeadDepth;
}
public class ConicalHead extends Head {
private float conicalHeadHeight;
}
2 Answers 2
I prefer to validate in the constructor. The idea behind that is then you know that the object state is valid because the object exists.
Now maybe you can’t validate at the client for some reason. Fine. Create a different type to hold this non-validated data. Some call it a request model. Some call it a DTO. Heck it can be a key value hash table. Whatever you call this data structure it’s what the server takes and passes into the factory to build the validated Head
object.
The factory can then return a ConicalHead
or a DishedHead
.
Alternatively you could just model a dished head with a negative head height. Saves you from creating a FlatHead
type.
The serious thing to think about isn’t the data. It’s how these types will be used. This data should be private. Encapsulated. But there should still be useful things you can tell Head
to do.
Look at the using code before you settle on a design for this Head
. Or you’ll just end up giving up and giving it a bunch of public getters.
I got a suggestion to use Factory design pattern; but because every class has different variables, I don't think that is the right direction.
Is the confusion fundamentally about polymorphism? That is, doing the same thing but differently. This is about methods, not properties.
Here's what it looks like (warning: probable invalid Java syntax)
Head dishTank = TankFactory.Create( headType.Dish );
Head flatTank = TankFactory.Create( headType.Flat );
dishTank.Validate(); // dish-specific validation
flatTank.Validate(); // flat-specific validation
Here is the "code behind" for the above:
public enum headType { Dish, Conical, Flat }
public class TankFactory {
public Head Create( headType thisKind ) {
Head tanked;
switch( thisKind ) {
case headType.Dish : {
tanked = new DishedHead( thisKind ) ;
break;
}
case headType.Flat: {
tanked = new FlatHead( thisKind )
break;
}
} // switch
return tanked;
}
}
public class Head {
public headType whatAmI;
// ignore other properties
public Head( headType thisKind ) {
whatAmI = thisKind;
}
public bool Validate() { ... } // this will be over-ridden
}
public class DishedHead extends Head {
private float dishedHeadDepth;
public DishedHead(headType thisKind) {
super( thisKind );
}
// class properties are in scope. Parameters not needed.
public bool Validate() { dished specific code }
}
public class FlatHead extends Head {
private float flatHeadHeight;
public FlatHead( headType thisKind ) {
super( thisKind );
}
// class properties are in scope. Parameters not needed.
public bool Validate() { flat head specific validation }
}
Explore related questions
See similar questions with these tags.
type
field within the data typed in. You use it to differentiate the Child classes for Head. Once you have the new object, you can forward all input data. The object will know how to use the input data, because it's dedicated data for that particular class. But this seems too simple. Maybe I'm overlooking something.