Some days ago I have decided to take a look at one of the homeworks problem of the OOP course at SoftUni. Then, I have decided to solve it with my VBA OOP knowledge, implementing it in C#. Whether VBA is an OOP language, is an opened discussion with multiple opinions.
This is how the problem looked like:
Problem Definition
Write a program that models 2 vehicles (a Car and a Truck) and simulates driving and refueling them. Car and truck both have fuel quantity, fuel consumption in liters per km and can be driven a given distance and refueled with a given amount of fuel. It’s summer, so both vehicles use air conditioners and their fuel consumption per km is increased by 0.9 liters for the car and with 1.6 liters for the truck. Also, the truck has a tiny hole in its tank and when its refueled it keeps only 95% of the given fuel. The car has no problems and adds all the given fuel to its tank. If a vehicle cannot travel the given distance, its fuel does not change.
Input
- On the first line – information about the car inthe format: “Car {fuel quantity} {liters per km}”
- On the second line – info about the truck inthe format: “Truck {fuel quantity} {liters per km}”
- Onthe third line – the number of commands N that will be given on the next N lines
- On the next N lines – commands in the format:
- “Drive Car {distance}”
- “Drive Truck {distance}”
- “Refuel Car {liters}”
- “Refuel Truck {liters}”
Output
- After each Drivecommand, if there was enough fuel, print on the console a message in the format:
- “Car/Truck travelled {distance} km”
- Iftherewas not enough fuel,print: “Car/Truck needs refueling”
- After the End command, print the remaining fuel for both the car and the truck, rounded to 2 digits after the floating point in the format:
- “Car: {liters}”
- “Truck: {liters}”
Examples
Input | Output |
Car 15 0.3 Truck 100 0.9 4 Drive Car 9 Drive Car 30 Refuel Car 50 Drive Truck 10 | Car travelled 9 km Car needs refueling Truck travelled 10 km Car: 54.20 Truck: 75.00 |
Car 30.4 0.4 Truck 99.34 0.9 5 Drive Car 500 Drive Car 13.5 Refuel Truck 10.3 Drive Truck 56.2 Refuel Car 100.2 | Car needs refueling Car travelled 13.5 km Truck needs refueling Car: 113.05 Truck: 109.13 |
My implementation
was to make a parent class Auto and to inherit from it the classes Car and Truck. In these, I had separate functions for checking the fuel, driving and the overriding of the ToString(). The Main function is pretty neat:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
static void Main() { Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); List<string> carInfo = ReadLineAndParseToList(); List<string> truckInfo = ReadLineAndParseToList(); Car car = new Car(decimal.Parse(carInfo[1]), decimal.Parse(carInfo[2])); Truck truck = new Truck(decimal.Parse(truckInfo[1]), decimal.Parse(truckInfo[2])); int commandCounts = int.Parse(Console.ReadLine()); for (int i = 0; i < commandCounts; i++) { CommandReader(ReadLineAndParseToList(),car,truck); } Console.WriteLine(car.ToString()); Console.WriteLine(truck.ToString()); } |
Still, there are other functions, which were not that good – DriveInfo() and WriteFuelRequest() were taking the typeOfAuto as a string, which seemed somehow bad, as there should be another way:
1 2 3 4 5 6 7 8 9 |
public string DriveInfo(string typeOfAuto, decimal distance) { return $"{typeOfAuto} travelled {distance} km"; } public string WriteFuelRequest(string typeOfAuto) { return $"{typeOfAuto} needs refueling"; } |
There were some other tiny smells, which I was not happy with, but as far as it passed the test, I was more eager to take a look at the original solution. The whole code is here.
Original Solution
So, I was curious to see the original solution and to see what could be learned from it. First thing that I liked there was putting the Car, Truck and Vehicle classes in a Model folder. This was a good practice, following the structure of the EF.
Then the overriding of the Refuel() method for the truck was done pretty neatly – it actually used the original method and added a line for the wasted fuel:
1 2 3 4 5 |
public override void Refuel(double amount) { base.Refuel(amount); this.FuelQuantity -= amount * wastedFuel; } |
The constructor of the Car() and the Truck() uses the base constructor, adding the air conditioning consumption. Thus, no additional logic is needed for the air conditioning later. In my solution I put it in the driving logic:
1 2 3 4 5 6 7 |
public void Drive(decimal distance) { DrivenDistance += distance; FuelQuantity -= distance * AirConditionPerKm; FuelQuantity -= distance * LitersPerKm; Console.WriteLine(DrivenDistance); } |
but in general, probably the correct building of the constructor was a bit better:
1 2 |
public Truck(double fuelQuantity, double fuelConsumption) : base(fuelQuantity, fuelConsumption + airConditionConsumption){} |
The last thing I liked from the original solution was the reflection for the ToString() overriding:
1 2 3 4 |
public override string ToString() { return $"{this.GetType().Name}: {this.FuelQuantity:F2}"; } |
Indeed, it is useful this way, although one be careful with using it – the parent class should not know a lot about its children.
In general, this is it. The idea of this article is to show, that after solving a problem yourself, there is always something to learn from any other solution of the same problem. A way to go.
Cheers! 🙂