问题
We have a business model that requires, say, different types of vehicles to be identified. For example, motorcycle, boat, yacht, farm equipment, snowmobiles, heavy truck, light truck, passenger car, and "Other".
I think there are two ways to handle it: Create a Vehicle class with a few subclasses, say, boat, truck, car and have a single enum indicating the actual type. This would work, allowing you to represent vehicles that share some common features with common subclasses. But it allows you to have mismatched enums with the classes.
I think the traditional way to handle it is to have a separate subclass for each type, which may subclass the vehicle, or a subclass of vehicle. For example, heavy and light truck might subclass truck; boat and yacht might subclass boat; snowmobile might subclass vehicle. The problem is, it doesn't really lend itself to representing the concept of other.
Does anyone have any patterns or best-practices for these sorts of scenarios?
Peter
EDIT: The purpose of the object is to convey information about the vehicle and to be able to display that information in a user-friendly way. For example, pull the data from a database and display it on a screen to be viewed/edited.
This leads to another downside to the traditional OO means that leans away from type indicators for actual types, in that to display the type one would need to perform some sort of instance-of and convert the value to something user-friendly.
(Also, clarified I was talking about a single enum, not an enum per subclass.)
回答1:
The Real Question
How different do two "things" need to be before they deserve their own class?
The Answer
It depends entirely on how you are going to use the objects.
- Will you be comparing them based on some property they have (e.g., does it float?)? If so, a single class with a differentiating property makes sense.
- Are you going to display your objects on an interface? Would it make sense within your application to display Light Trucks and Heavy Trucks in a single table? If they cannot meaningfully exist and be displayed as one data set, then it makes sense to have two classes.
Those are just two examples. The point is, if you create a new class, it should be useful. Java is particularly prone to over-abstraction.
What do I do about Other
?
Other sounds like a group of Vehicles that are not Trucks and not Cars. It sounds like you want to catch all other Vehicles and put them in one class. Why not use the Vehicle class? Don't create another class that derives from Vehicle but adds zero functionality. The same usefulness test applies here.
- Is a
Vehicle
useful enough to satisfy my needs for all "other" vehicles? If not, I need to create more classes.
I took your advice and created two useful classes. Now, I can't tell them apart and I refuse to use instanceof. What do I do?
No matter how abstracted your classes are, I will always be able to add instances your class to a List<Object>
and will then be unable to tell them apart. You cannot bulletproof your design.
Let me put it another way - if you add Eggs and Cars to a List, and you later need to differentiate between Eggs and Cars, then there is a problem with your List, not the Eggs and Cars.
回答2:
I would start with a Vehicle and not add too much abstraction.
I wouldn't use the class hierarchy to describe something you could use a field to describe.
Is the code for these types so different?
For example, say you have a type you didn't think of before. like an aqua-car (which is a car which can travel over water) or a seyway, or a unicycle. You could create a new class for each type or you could have it entirely data driven with fields like
name: aqua-car
type: Exotic Car
travelsOnWater: true
travelsOdLand: true
wheels: 4
I suggest you read You Ain't Gonna Need It Better to add only the abstraction you need, not the abstraction you can imagine.
回答3:
There is not simple answer for your question. Because its depend on the business logic you will have to perform with that data structure.
I would start with an interface Vehicle
that will resolve a Identyficator from to get the description of concrete representant.
interface VehicleIdentyficator {
String identyficator();
}
interface Vehicle {
Identyficator getIdentyficator();
}
With this you are not limited to class, enum or other kind of design.
Then i would use class hierarchy to describe the properties of each vehicle.
After that add some logic/behavioural aspects to the code and get a look that my data structures are valid for the task.
At the end of the day the important aspect is to perform some operations.
For example there is no point of creation three classes Truck, LightTruck and HavyTruck.
You could create a class that describe them by task they perform
- They can transport on ground
- The Light truck can carry less load but it used to travel in small cities.
- The Heavy truck is opposite to Light. Have big Range carry more load.
When we compare to this a boat we see that boat is more like light truck the only difference is that it travel on water.
So try to understand the object not be what it is but what it can do. What tasks can be performed by it and what are the limitation. Then with your design will be really close to what you need.
I hope this sentence is correct and i will repeat myself. It seams that you are using those vehicles, not constructing them. So focus on their mission to full fill not on their physical aspects.
But you can do something like this
enum VechicleType implements VehicleIdentyficator {
TRUCK("TRUCK"),
HEAVY_TRUCK("HEAVY_TRUCK")
private final String indentyficator;
private VechicleType(String indetyficator) {
this.indentyficator = identyficator;
}
public String identyficator() {
return indentyficator;
}
}
But then every time you add some new vehicle you must cover all points where such new hard coded type will be used.
回答4:
As others stated, I think it depends on how you're gonna use your vehicles.
If you just need to distinguish between types at some points, but you mostly handle all vehicles the same way, go for the enum type.
If you really need to specify different behaviors and you make use of shared features/behaviors, go for a full class hierarchy. That's also my preferred approach, because I feel like it offers more evolutivity.
回答5:
The best way to handle type indicators in OO development is to not have type indicators. Type indicators are a structured programming (that think that predates object oriented programming) concept. In OO, type is identified by type, not by an artificial indicator.
Edit:
If you have a fixed domain of things that you must represent with an object (for example: tractor, speed boat, row boat, motorcycle, mazda 626, pickup truck, deuce-and-a-half truck) then you can (perhaps should) represent each thing with a concrete class. The interesting design question will be based on what you need to do with the objects.
If you just need to know "is this a water vehicle" or "how many wheels does this have" then use an Interface with isWaterVehicle()
, getWheelCount()
, isTruck()
methods. Implement the interface on your objects and hard code the answer. For example:
class SpeedBoat implements VehicleInfo
{
public int getWheelCount()
{
return 0;
}
public boolean isTruck()
{
return false;
}
public boolean isWaterVehicle()
{
return true;
}
}
If you have a large number of similar objects, use an abstract class to set the defaults.
abstract class AbstractTruck implements VehicleInfo
{
public final int isTruck()
{
return true;
}
}
来源:https://stackoverflow.com/questions/23367491/whats-the-best-way-to-handle-type-indicators-in-object-oriented-design