# Exercise: Abstraction

Finish a city bike share. Make Vehicle an abstract class that every kind of vehicle prices for itself, give the electric ones the IChargeable contract, and write a RideService that gets its time from an IClock.

Journeyman · C# · OOP · Updated October 30, 2026

A city bike share rents out bikes, e-bikes and scooters. Each kind has its own prices, and the electric ones have batteries that run down as they're ridden. You'll use all three tools from this chapter: an abstract class, an interface, and a dependency injected through an interface.

## Get the exercise code

Open this lesson's GitHub repository, [github.com/ask-codey/exercise-abstraction](https://github.com/ask-codey/exercise-abstraction), also linked from the **Exercise** box beside the lesson. Click **Code**, then **Download ZIP**, and unzip it into your `bootcamp` folder. Or clone it with Git. Then open `BikeShare.slnx` in Visual Studio.

| File | What's in it |
|---|---|
| `BikeShare/Vehicle.cs` | Every kind of vehicle, for you to finish |
| `BikeShare/Bike.cs` | A finished kind of vehicle, to use as an example |
| `BikeShare/EBike.cs`, `Scooter.cs` | The electric vehicles, for you to finish |
| `BikeShare/IChargeable.cs` | The contract for anything with a battery, finished |
| `BikeShare/IClock.cs`, `SystemClock.cs` | The clock's contract and the real clock, finished |
| `BikeShare/RideService.cs` | Starts and ends rides, for you to finish |
| `BikeShare.Tests` | Tests for all of it, with a fake clock |

The requirements are in the comment at the top of each file you finish.

## What to do

| Step | What it does |
|---|---|
| 1. `Vehicle` | Make it **abstract**, with abstract `UnlockFee` and `PricePerMinute`. `RideCost(minutes)` is the unlock fee plus the price for every minute. |
| 2. `EBike`, `Scooter` | Their prices, and the **`IChargeable`** contract: a battery that starts at 100%, drains 1% (e-bike) or 2% (scooter) a minute but never below 0%, and charges back to 100%. |
| 3. `RideService` constructor | It's given an **`IClock`**, but ignores it. Keep the one it's given. |
| 4. `StartRide`, `EndRide` | Remember when each ride starts. When it ends, charge for every minute, counting part of a minute as a whole one, and drain the battery if it has one. |
| 5. `NeedCharging` | The vehicles in a fleet that have a battery under 20%. |

Run the program with **Ctrl+F5** to see the prices, and the tests with **Test > Run All Tests**.

## Hints

- **Start with `Vehicle`.** Once it's abstract, `EBike` and `Scooter` stop compiling until they override its abstract members. That's the compiler holding them to the rules. Press **Ctrl+.** on the red line and choose **Implement abstract class** to get started.
- **Base class first, then interfaces:** `class EBike : Vehicle, IChargeable`.
- **`EndRide` doesn't care what kind of vehicle it has.** `vehicle.RideCost(minutes)` prices any kind, and `vehicle is IChargeable battery` tells it whether there's a battery to drain.
- **The tests move a fake clock forward:** they start a ride, add 12 minutes to the clock, and end it. That only works if `RideService` asks the clock it was given.
- A `Dictionary<string, DateTime>` keyed by the vehicle's `Id` can remember the start times. `TryAdd` and `Remove` return whether they did anything, which answers the "already on a ride" and "not on a ride" rules.
- **To refuse,** stop the method with `throw new InvalidOperationException("B1 is already on a ride.");`. The program stops there with that message, unless some code catches it. The next chapter, *Files and Exceptions*, covers exceptions properly.

## When you're done

Every test passes, and the program prints:

```text
B1: a 20-minute ride costs $4.00
E1: a 20-minute ride costs $8.00
E1: 55% left after 45 minutes
S1: a 20-minute ride costs $6.50
S1: 10% left after 45 minutes
Needs charging: S1
```

Look at `EndRide`: it works for bikes, e-bikes and scooters without asking which is which, and it would work for a new kind of vehicle tomorrow, battery or not.

## Submit your exercise

The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.

1. On GitHub, click **+**, then **New repository**. Name it (for example `exercise-abstraction`), choose **Public**, and click **Create repository**. Leave out the README: your folder already has one.
2. In a terminal in your exercise folder (Git Bash on Windows), send your work to your new repo. If you downloaded the ZIP:

   ```bash
   git init -b main
   git add .
   git commit -m "My solution"
   git remote add origin https://github.com/your-name/exercise-abstraction.git
   git push -u origin main
   ```

   If you cloned the starter instead, point your copy at your own repo, then commit and push:

   ```bash
   git remote set-url origin https://github.com/your-name/exercise-abstraction.git
   git add .
   git commit -m "My solution"
   git push -u origin main
   ```

3. Paste your repo's address, such as `https://github.com/your-name/exercise-abstraction`, into **Submit your exercise** on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.

Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.

## So what

The abstract class makes every vehicle price itself, the interface marks the ones with batteries, and `IClock` lets the tests decide what time it is. Three small contracts, and the code that uses them never needs to know more.

## Key terms

- [Interface](https://www.ask-codey.com/glossary/interface-c-sharp)
- [Dependency Injection](https://www.ask-codey.com/glossary/dependency-injection)

## Related

- [Adding Abstraction](https://www.ask-codey.com/lessons/abstraction-in-csharp-adding-abstraction)
- [Polymorphism with Interfaces](https://www.ask-codey.com/lessons/interfaces-in-csharp-polymorphism-with-interfaces)
- [Exercise: Dependency Injection](https://www.ask-codey.com/lessons/exercise-dependency-injection)

Source: https://www.ask-codey.com/lessons/exercise-abstraction
