diff --git a/src/main/kotlin/ru/otus/cars/Car.kt b/src/main/kotlin/ru/otus/cars/Car.kt index 559978c..64e98cc 100644 --- a/src/main/kotlin/ru/otus/cars/Car.kt +++ b/src/main/kotlin/ru/otus/cars/Car.kt @@ -19,6 +19,11 @@ interface Car : CarInput { */ val carOutput: CarOutput + /** + * Горловина бака + */ + val tankMouth: TankMouth + /** * Получить оборудование */ diff --git a/src/main/kotlin/ru/otus/cars/CarOutput.kt b/src/main/kotlin/ru/otus/cars/CarOutput.kt index 875339f..9a4acf3 100644 --- a/src/main/kotlin/ru/otus/cars/CarOutput.kt +++ b/src/main/kotlin/ru/otus/cars/CarOutput.kt @@ -8,4 +8,9 @@ interface CarOutput { * Скажи текущую скорость */ fun getCurrentSpeed(): Int + + /** + * Скажи текущий уровень топлива + */ + fun getFuelLevel(): Int } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/FuelSystem.kt b/src/main/kotlin/ru/otus/cars/FuelSystem.kt new file mode 100644 index 0000000..9562f89 --- /dev/null +++ b/src/main/kotlin/ru/otus/cars/FuelSystem.kt @@ -0,0 +1,55 @@ +package ru.otus.cars + +/** + * Бак машины. + */ +internal interface Tank { + /** + * Горловина, установленная на бак. + */ + val mouth: TankMouth + + /** + * Содержимое бака в литрах. + */ + fun getContents(): Int + + /** + * Принять топливо. + */ + fun receiveFuel(liters: Int) +} + +/** + * Горловина бака определяет, какое топливо можно заливать в машину. + */ +sealed class TankMouth protected constructor(private val tank: Tank) { + internal fun fill(liters: Int) { + tank.receiveFuel(liters) + } + + class Petrol internal constructor(tank: Tank) : TankMouth(tank) + + class Gas internal constructor(tank: Tank) : TankMouth(tank) +} + +internal class SimpleTank( + private val capacity: Int = 50, + mouthFactory: (Tank) -> TankMouth, +) : Tank { + override val mouth: TankMouth = mouthFactory(this) + + private var fuelLevel: Int = 0 + + override fun getContents(): Int { + return fuelLevel + } + + override fun receiveFuel(liters: Int) { + require(liters > 0) { "Количество топлива должно быть положительным" } + + fuelLevel = (fuelLevel + liters).coerceAtMost(capacity) + } +} + +class BrokenTankException(message: String) : RuntimeException(message) \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/GasStation.kt b/src/main/kotlin/ru/otus/cars/GasStation.kt new file mode 100644 index 0000000..62817c2 --- /dev/null +++ b/src/main/kotlin/ru/otus/cars/GasStation.kt @@ -0,0 +1,25 @@ +package ru.otus.cars + +/** + * Заправка. + */ +object GasStation { + fun fill(car: Car, liters: Int) { + try { + when (val mouth = car.tankMouth) { + is TankMouth.Gas -> fillGas(mouth, liters) + is TankMouth.Petrol -> fillPetrol(mouth, liters) + } + } catch (e: BrokenTankException) { + println("Заправка безопасно остановлена: ${e.message}") + } + } + + private fun fillGas(mouth: TankMouth.Gas, liters: Int) { + mouth.fill(liters) + } + + private fun fillPetrol(mouth: TankMouth.Petrol, liters: Int) { + mouth.fill(liters) + } +} \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Taz.kt b/src/main/kotlin/ru/otus/cars/Taz.kt index 49df937..f9425f0 100644 --- a/src/main/kotlin/ru/otus/cars/Taz.kt +++ b/src/main/kotlin/ru/otus/cars/Taz.kt @@ -1,6 +1,18 @@ package ru.otus.cars object Taz: Car { + private object ExplodingTank : Tank { + override val mouth: TankMouth = TankMouth.Petrol(this) + + override fun getContents(): Int { + return 0 + } + + override fun receiveFuel(liters: Int) { + throw BrokenTankException("Бак ТАЗа взорвался") + } + } + /** * Номерной знак */ @@ -15,8 +27,20 @@ object Taz: Car { /** * Следит за машиной */ - override val carOutput: CarOutput - get() = throw NotImplementedError("Приборов нет") + override val carOutput: CarOutput = object : CarOutput { + override fun getCurrentSpeed(): Int { + return 0 + } + + override fun getFuelLevel(): Int { + return ExplodingTank.getContents() + } + } + + /** + * Горловина бака + */ + override val tankMouth: TankMouth = ExplodingTank.mouth /** * Получить оборудование @@ -36,4 +60,8 @@ object Taz: Car { override fun wheelToLeft(degrees: Int) { throw NotImplementedError("Руля нет") } + + override fun toString(): String { + return "Taz(color=$color, fuelLevel=${carOutput.getFuelLevel()})" + } } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Vaz2107.kt b/src/main/kotlin/ru/otus/cars/Vaz2107.kt index be857d2..fddcba6 100644 --- a/src/main/kotlin/ru/otus/cars/Vaz2107.kt +++ b/src/main/kotlin/ru/otus/cars/Vaz2107.kt @@ -5,7 +5,10 @@ import kotlin.random.Random /** * Семёрочка */ -class Vaz2107 private constructor(color: String) : VazPlatform(color) { +class Vaz2107 private constructor( + color: String, + private val tank: Tank, +) : VazPlatform(color) { /** * Сам-себе-сборщик ВАЗ 2107. */ @@ -17,7 +20,10 @@ class Vaz2107 private constructor(color: String) : VazPlatform(color) { } } - override fun build(plates: Car.Plates): Vaz2107 = Vaz2107("Зеленый").apply { + override fun build(plates: Car.Plates): Vaz2107 = Vaz2107( + color = "Зеленый", + tank = SimpleTank { TankMouth.Gas(it) }, + ).apply { this.engine = getRandomEngine() this.plates = plates } @@ -50,6 +56,11 @@ class Vaz2107 private constructor(color: String) : VazPlatform(color) { private var currentSpeed: Int = 0 // Скока жмёт + /** + * Семерка ездит на газу. + */ + override val tankMouth: TankMouth = tank.mouth + /** * Доступно сборщику * @see [build] @@ -59,7 +70,7 @@ class Vaz2107 private constructor(color: String) : VazPlatform(color) { // Выводим состояние машины override fun toString(): String { - return "Vaz2107(plates=$plates, wheelAngle=$wheelAngle, currentSpeed=$currentSpeed)" + return "Vaz2107(plates=$plates, wheelAngle=$wheelAngle, currentSpeed=$currentSpeed, fuelLevel=${tank.getContents()})" } /** @@ -74,5 +85,9 @@ class Vaz2107 private constructor(color: String) : VazPlatform(color) { override fun getCurrentSpeed(): Int { return this@Vaz2107.currentSpeed } + + override fun getFuelLevel(): Int { + return this@Vaz2107.tank.getContents() + } } } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Vaz2108.kt b/src/main/kotlin/ru/otus/cars/Vaz2108.kt index 27b83b8..5e93897 100644 --- a/src/main/kotlin/ru/otus/cars/Vaz2108.kt +++ b/src/main/kotlin/ru/otus/cars/Vaz2108.kt @@ -5,7 +5,10 @@ import kotlin.random.Random /** * Восьмерка */ -class Vaz2108 private constructor(color: String) : VazPlatform(color) { +class Vaz2108 private constructor( + color: String, + private val tank: Tank, +) : VazPlatform(color) { /** * Сам-себе-сборщик ВАЗ 2108. */ @@ -18,7 +21,10 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { } } - override fun build(plates: Car.Plates): Vaz2108 = Vaz2108("Красный").apply { + override fun build(plates: Car.Plates): Vaz2108 = Vaz2108( + color = "Красный", + tank = SimpleTank { TankMouth.Petrol(it) }, + ).apply { this.engine = getRandomEngine() this.plates = plates } @@ -54,6 +60,11 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { private var currentSpeed: Int = 0 // Скока жмёт + /** + * Восьмерка ездит на бензине. + */ + override val tankMouth: TankMouth = tank.mouth + /** * Доступно сборщику * @see [build] @@ -63,7 +74,7 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { // Выводим состояние машины override fun toString(): String { - return "Vaz2108(plates=$plates, wheelAngle=$wheelAngle, currentSpeed=$currentSpeed)" + return "Vaz2108(plates=$plates, wheelAngle=$wheelAngle, currentSpeed=$currentSpeed, fuelLevel=${tank.getContents()})" } /** @@ -78,5 +89,9 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { override fun getCurrentSpeed(): Int { return this@Vaz2108.currentSpeed } + + override fun getFuelLevel(): Int { + return this@Vaz2108.tank.getContents() + } } } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/main.kt b/src/main/kotlin/ru/otus/cars/main.kt index 978d0ef..fe0d17d 100644 --- a/src/main/kotlin/ru/otus/cars/main.kt +++ b/src/main/kotlin/ru/otus/cars/main.kt @@ -16,6 +16,8 @@ fun main() { techChecks() println("\n===> Taz...") println(Taz.color) + println("\n===> fill cars...") + fillCars() } fun driveCars() { @@ -90,4 +92,26 @@ fun repairEngine(car: VazPlatform) { is VazEngine.LADA_2107 -> println("Чистка карбюратора у двигателя объемом ${car.engine.volume} куб.см у машины $car") is VazEngine.SAMARA_2108 -> println("Угол зажигания у двигателя объемом ${car.engine.volume} куб.см у машины $car") } +} + +fun fillCars() { + val cars = listOf( + Togliatti.buildCar(Vaz2107, Car.Plates("777", 77)), + Togliatti.buildCar(Vaz2108, Car.Plates("888", 78)), + Taz, + ) + + println("До заправки:") + cars.forEach { car -> + println(car) + } + + cars.forEach { car -> + GasStation.fill(car, liters = 30) + } + + println("После заправки:") + cars.forEach { car -> + println(car) + } } \ No newline at end of file