1 /* 2 * * Copyright 2022 Google LLC. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the License); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package beer 18 19 import dagger.Binds 20 import dagger.Component 21 import dagger.Lazy 22 import dagger.Module 23 import dagger.Provides 24 import javax.inject.Inject 25 import javax.inject.Singleton 26 27 interface Grains { 28 val name: String 29 } 30 31 interface Hops { 32 val name: String 33 } 34 35 interface Yeast { 36 val name: String 37 } 38 39 interface Kettle { steepnull40 fun steep() 41 fun heat() 42 fun boil() 43 fun cool() 44 fun ferment() 45 fun addGrains(grains: Grains) 46 fun addHops(hops: Hops) 47 fun addYeast(yeast: Yeast) 48 val isBoiling: Boolean 49 val hasCooled: Boolean 50 val isDone: Boolean 51 } 52 53 interface Storage { 54 fun store() 55 } 56 57 class PilsnerMalt 58 @Inject constructor() : Grains { 59 override val name get() = "Pilsner Malt" 60 } 61 62 class Spalt 63 @Inject constructor() : Hops { 64 override val name get() = "Spalt" 65 } 66 67 class Wyeast 68 @Inject constructor() : Yeast { 69 override val name get() = "Wyeast 2565 Kölsch" 70 } 71 72 class BrewPot : Kettle { 73 var boiling: Boolean = false 74 var cool: Boolean = true 75 var done: Boolean = false 76 addGrainsnull77 override fun addGrains(grains: Grains) { 78 println("Adding grains: " + grains.name) 79 } 80 steepnull81 override fun steep() { 82 println("=> Steeping") 83 } 84 heatnull85 override fun heat() { 86 println("=> Heating") 87 this.cool = false 88 } 89 boilnull90 override fun boil() { 91 println("=> Boiling") 92 this.boiling = true 93 } 94 coolnull95 override fun cool() { 96 println("=> Cooling") 97 this.boiling = false 98 this.cool = true 99 } 100 addHopsnull101 override fun addHops(hops: Hops) { 102 println("Adding hops: " + hops.name) 103 } 104 fermentnull105 override fun ferment() { 106 println("=> Fermenting") 107 this.done = true 108 } 109 addYeastnull110 override fun addYeast(yeast: Yeast) { 111 println("Adding yeast: " + yeast.name) 112 } 113 114 override val isBoiling get() = boiling 115 override val hasCooled get() = cool 116 override val isDone get() = done 117 } 118 119 class Bottler 120 @Inject constructor( 121 private val kettle: Kettle 122 ) : Storage { storenull123 override fun store() { 124 if (kettle.isDone) { 125 println("=> bottling") 126 } 127 } 128 } 129 130 class BeerBrewer 131 @Inject constructor( 132 private val kettle: Lazy<Kettle>, 133 private val bottler: Bottler, 134 private val grains: Grains, 135 private val hops: Hops, 136 private val yeast: Yeast 137 ) { brewnull138 fun brew() { 139 kettle.get().apply { 140 addGrains(grains) 141 steep() 142 heat() 143 boil() 144 if (isBoiling) addHops(hops) 145 cool() 146 if (hasCooled) addYeast(yeast) 147 ferment() 148 } 149 bottler.store() 150 } 151 } 152 153 @Module 154 abstract class CommercialEquipmentModule { 155 @Binds provideStoragenull156 abstract fun provideStorage(storage: Bottler): Storage 157 } 158 159 @Module(includes = [CommercialEquipmentModule::class]) 160 class BrewingEquipmentModule { 161 @Provides @Singleton 162 fun provideKettle(): Kettle = BrewPot() 163 } 164 165 @Module 166 interface KolschRecipeModule { 167 @Binds bindGrainsnull168 fun bindGrains(grains: PilsnerMalt): Grains 169 170 @Binds 171 fun bindHops(hops: Spalt): Hops 172 173 @Binds 174 fun bindYeast(yeast: Wyeast): Yeast 175 } 176 177 @Singleton 178 @Component(modules = [BrewingEquipmentModule::class, KolschRecipeModule::class]) 179 interface Brewery { 180 fun brewery(): BeerBrewer 181 } 182 mainnull183fun main(args: Array<String>) { 184 val beer = DaggerBrewery.builder().build() 185 beer.brewery().brew() 186 } 187