1

I am working on low level design of cab booking type of system and feeling stuck at modelling Vehicle in Booking class.I came up with following design.

    Class Vehicle
    {
        
        
    }
    Class Car extends Vehicle
    {
        CAR_TYPE type;
    }
    Classs Bike extends Vehicle
    {
        
    }
    Class Auto extends Vehicle
    {
        
    }
    Class CAR_TYPE
    {
    HATCHBACK,
    SEDAN,
    SUV,
    XUV
    }
    Class Booking
    {
        int number;
        ...
        ....
        Vehicle Vehicle;
        VehicleType type;
        ...
        ...
    }
    enum VehicleType
    {
        CAR,
        BIKE,
        AUTO
        
    }

Now to see, which vehicle is used for booking, we can see the VehicleType from booking and then typecast the vehicle to that object(CAR,BIKE,AUTO).Is it a bad way model?

In general, if we have a reference to parent, and we want to know specific child class which is holds,is this a good way to do?Are there alternate approaches ?

6
  • 2
    Is there a difference in behavior between the types? Are you not able to use the abstraction Vehicle for all user cases? Feb 27, 2021 at 18:06
  • I want to store CAR_TYPE in car, so thats why i cannot use Vehicle abstraction. I have update the question.I have faced this problem earlier also,but i neglected it.I want to know how can we handle it in nice way
    – stkUser
    Feb 27, 2021 at 18:12
  • Why does the car type matter? Customer preference? Feb 27, 2021 at 19:31
  • Yeah it matters, and car may be 2-3 extra attributes also.Consider it as a general case that may not be specific to this problem.I am sure there can be lot of use cases around this problem?
    – stkUser
    Feb 27, 2021 at 20:50
  • 1
    Not to throw fuel on a fire ... or add to confusion ... but remember in Java (and Java alone, pretty much!) enum values are instances of a class and can have behavior! They're not as limited as they are in C/C++/etc. .... There are reasons to not use an enum in this use case, for generality in the future, but in Java the consequences aren't quite the same as in other languages ...
    – davidbak
    Feb 27, 2021 at 23:49

4 Answers 4

2

Why it's not the best way?

Getting the type from the parent (Booking) and type-casting/down-casting the child (Vehicle) to its true type (e.g. Car) works but it's not the best way, because:

  • It does not allow to freely extend Vehicle: if tomorrow, you'd want to book also Boats or Trucks you'd need to check and update all the code using Booking. If not, you'd risk some failures (e.g. a Booking instance uses a Boat, but the client code doesn't expect it raises and exception (or does wrong downcast). This is not in line with the open/closed principle.
  • Moreover it requires the classes to know a lot about its neighbours (Booking) and the neighbours of your neighbours (Vehicle) and its possible specializations. This is not in line with the principle of least knowledge.

What are the alternatives?

Your question does not provide enough information to propose the best alternatives. But here some approaches:

  • Tell, don't ask!: instead of asking and asking and do yourself a part of the processing logic, tell the Booking what you want, let the Booking tell the Vehicle what it shall do accordingly, and let polymorphism drive the objects to do what is needed depending on their type.

  • If polymorphism is not sufficient, because some Car behaviors do not exist for Bike or Boat, you may consider:

    • using a strategy for Booking that is adapted to the type of Vehicle, and inject this strategy togeter with the Vehicle.
    • using a visitor pattern to process the composite structure made of Booking and its associated objects
    • having specialization of Booking that correspond to the appropriate specialization of Vehicle (e.g. CarBooking for Car, BikeBooking for Bike). Typically, you'd use an abstract factory pattern to create families of related objects (e.g. specialized Booking and specialized Vehicle).
0

Here’s what you do: You accept that right now you don’t know yet what you need, and make sure that you can adapt to what you need when you figure it out.

For the booking, for example, I wouldn’t store car type and vehicle type but an abstract type describing what the customer wants. Which might include “not red”. In the future. If designed right, your code will survive that change with no code change.

2
  • 1
    But for booking class we need to know what vehicle has been used.I dont know what you mean by "not red"?Can you elaborate?
    – stkUser
    Feb 27, 2021 at 19:06
  • I dont think in this particular case so detailed explicit modeling is nessesary. He should start generic define one column as discriminator so that in the future he can go concrete. Feb 27, 2021 at 22:56
0

In my opinion from a booking perspective you don't realy need to model via inheritence each individual transport type. Are there any actions or functions attached to these transport types so that you need to model them explicitly? Same goes for the enum, do you want for any new transport type in the future to actually do a code change ?

In my opinion a more generic model will fit better in this case than trying to model each individual transport type.

Use one Class Vehicle with attribute Vehicle type1 that is a String like this:

public class Vehicle {

   private String vehicleClass;
   private String vehicleType;

}

If you need more data than this you can aways add a Map with vehicleAttributes or something around these lines.

By reserving one attribute as discriminator for example vehicleClass, in the future if you need a more concrete modeling you can introduce it.

4
  • I dont want Vehicle Type to be string.It can cause errors,I want it to be specific ENUM to make it error prone.One similar example i can show you ide.geeksforgeeks.org/c4izCUO2Mc . Here payment method is base and different classes are extending it.But there is a order class, which needs to know which payment method was used for payment.It is very similar to my above use case.My ENUMS are fixed and i dont want any more growth based on 2 wheeler ,3-wheeler, seats etc.Just in case, it is car, i need to maintain some info specific to car.
    – stkUser
    Feb 27, 2021 at 23:36
  • If you think that you will make it less error prone by using enum you are mistaken, but I dont want to start that discussion here. It is obvious you want to use inheritance and are seeking a valid argument to do that. The problem is that no-one here will actually give you that argument because there is no such argument based on the description of you question. The inheritance here is unneeded unless you actually tell us why you need it. The example you post for the credit cards is just an excersise. It maybe be that another developer will model it differently f.ex. using composition. Feb 27, 2021 at 23:50
  • ok after reading all the comments and answers ,i agree that ineritence may not be best for my use case.The example i posted for credit card is created by me yesterday.In that case i dont think inheritance is overkill.How would you recommend to handle that case of payment using composition?I did not get that
    – stkUser
    Feb 28, 2021 at 16:24
  • Nah... payment is a different domene I dont want to get there. I was trying to make a point that strong typing is not aways a good thing. I would suggest to focus yourself on the action and the behaviours. If an object does not exhibit a behaviour then maybe there is no need for so much modeling. In general @Christophe already went into a lot of details. Feb 28, 2021 at 16:28
0

All you need to do is accurately model your problem domain. Your problem domain appears to be some sort of taxi or ride sharing service, not manufacturing vehicles.

You do not need to perfectly model all the world's vehicles. Just enough for customers to choose the appropriate ride and book their trip.

By having sub types of Vehicle, you are saying that you expect behavioral differences between Car, Bike and Auto (you could argue that "car" and "automobile" are the same thing). You haven't stated what those differences are, but you should analyze whether they are differences in behavior or data. Differences in data should be captured in fields or properties of an object, not different types.

The customer only cares about whether the vehicle is a sedan, hatchback, truck, bike, etc. I would just have a VehicleType on a Vehicle object. No need for specialization beyond that. If you do need some sort of specialization consider putting that in the VehicleType enum. Certain operations on the Vehicle object could delegate to methods on the VehicleType enum for behavior specific to that kind of vehicle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.