object MySingelton
interface Animal {
val id : Int
val name : String
}
class Cat(override val id: Int) : Animal {
// Same as before
}
class Dog(override val id: Int) : Animal {
// Same as before
}
class DogFactory {
fun createDog(breed: String, id: Int) = when(breed.trim().toLowerCase()) {
"beagle" -> Beagle(id)
"bulldog" -> Bulldog(id)
else -> throw RuntimeException("Unknown dog breed $breed")
}
}
class AnimalFactory {
var counter = 0
private val dogFactory = DogFactory()
private val catFactory = CatFactory()
fun createAnimal(animalType: String, animalBreed: String) : Animal {
return when(animalType.trim().toLowerCase()) {
"cat" -> catFactory.createDog(animalBreed, ++counter)
"dog" -> dogFactory.createDog(animalBreed, ++counter)
else -> throw RuntimeException("Unknown animal $animalType")
}
}
}
class NumberMaster {
companion object {
fun valueOf(hopefullyNumber: String) : Long {
return hopefullyNumber.toLong()
}
}
}
println(NumberMaster.valueOf("123")) // Prints 123
Example 1
Assume we have a configuration for our server written in a YAML file:
server:
port: 8080
environment: production
Our task is to construct objects from this configuration.
interface Property {
val name: String
val value: Any
}
interface ServerConfiguration {
val properties: List<Property>
}
data class PropertyImpl(
override val name: String,
override val value: Any
) : Property
data class IntProperty(
override val name: String,
override val value: Int
) : Property
data class StringProperty(
override val name: String,
override val value: String
) : Property
data class ServerConfigurationImpl(
override val properties: List<Property>
) : ServerConfiguration
class Parser {
companion object {
fun property(prop: String): Property {
val (name, value) = prop.split(":")
return when (name) {
"port" -> IntProperty(name, value.trim().toInt())
"environment" -> StringProperty(name, value.trim())
else -> throw RuntimeException("Unknown property: $name")
}
}
fun server(propertyStrings: List<String>):
ServerConfiguration {
val parsedProperties = mutableListOf<Property>()
for (p in propertyStrings) {
parsedProperties += property(p)
}
return ServerConfigurationImpl(parsedProperties)
}
}
}
val portProperty = Parser.property("port: 8080")
val portOrNull: Int? = portProperty.value as? Int
if (portOrNull != null) {
val port: Int = portOrNull // works
println(port)
}
val environment = Parser.property("environment: production")
println(environment)
val server = Parser.server(listOf("port: 8080", "environment: production"))
println(server)
interface Parser {
fun property(prop: String): Property
fun server(propertyStrings: List<String>): ServerConfiguration
}
class YamlParser : Parser {
// Implementation specific to YAML files
}
class JsonParser : Parser {
// Implementation specific to JSON files
}
/*
interface Parser {
fun property(prop: String): Property
fun server(propertyStrings: List<String>): ServerConfiguration
}
class YamlParser : Parser {
// Implementation specific to YAML files
}
class JsonParser : Parser {
// Implementation specific to JSON files
}
*/
Example 2
interface HQ {
fun buildBarracks(): Building<InfantryUnits, Infantry>
fun buildVehicleFactory(): Building<VehicleUnits, Vehicle>
}
class HQ {
val buildings = mutableListOf<Building<*, Unit>>()
// Original
fun buildBarracks(): Barracks {
val b = Barracks()
buildings.add(b)
return b
}
// Improved
fun buildBarracks(): Building<InfantryUnits, Infantry> {
val b = object : Building<InfantryUnits, Infantry> {
override fun build(type: InfantryUnits): Infantry {
return when (type) {
InfantryUnits.RIFLEMEN -> Rifleman()
InfantryUnits.ROCKET_SOLDIER -> RocketSoldier()
}
}
}
buildings.add(b)
return b
}
fun buildVehicleFactory(): VehicleFactory {
val vf = VehicleFactory()
buildings.add(vf)
return vf
}
fun buildVehicleFactory(): Building<VehicleUnits, Vehicle> {
val vf = object : Building<VehicleUnits, Vehicle> {
override fun build(type: VehicleUnits) = when (type) {
VehicleUnits.APC -> APC()
VehicleUnits.TANK -> Tank()
}
}
buildings.add(vf)
return vf
}
}
interface Unit
interface Vehicle : Unit
interface Infantry : Unit
class APC : Vehicle
class Tank : Vehicle
enum class VehicleUnits {
APC,
TANK
}
class Rifleman : Infantry
class RocketSoldier : Infantry
enum class InfantryUnits {
RIFLEMEN,
ROCKET_SOLDIER
}
class Barracks : Building<InfantryUnits, Infantry> {
override fun build(type: InfantryUnits): Infantry {
return when (type) {
RIFLEMEN -> Rifleman()
ROCKET_SOLDIER -> RocketSoldier()
}
}
}
val hq = HQ()
val barracks1 = hq.buildBarracks()
val barracks2 = hq.buildBarracks()
val vehicleFactory1 = hq.buildVehicleFactory()
interface Building<in UnitType, out ProducedUnit>
where UnitType : Enum<*>, ProducedUnit : Unit {
fun build(type: UnitType) : ProducedUnit
}
class Box<T> {
private var inside: T? = null
fun put(t: T) {
inside = t
}
fun get(): T? = inside
}
val box = Box<Cat>()
box.put(Cat())
val cat = box.get()
State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.
interface WhatCanHappen
fun seeHero()
fun getHit(pointsOfDamage: Int)
fun calmAgain()
}
class Snail : WhatCanHappen {
private var mood: Mood = Still
private var healthPoints = 10
override fun seeHero() {
mood = when(mood) {
is Still -> Aggressive
else -> mood
}
}
override fun getHit(pointsOfDamage: Int) {
healthPoints -= pointsOfDamage
mood = when {
(healthPoints <= 0) -> Dead
mood is Aggressive -> Retreating
else -> mood
}
}
override fun calmAgain() {
}
}
sealed class Mood {
// Some abstract methods here, like draw(), for example
}
object Still : Mood()
object Aggressive : Mood()
object Retreating : Mood()
object Dead : Mood()
/*
// Another approach
class Snail {
internal var mood: Mood = Still(this)
private var healthPoints = 10
// That's all!
}
sealed class Mood : WhatCanHappen
class Still(private val snail: Snail) : Mood() {
override fun seeHero() {
snail.mood = Aggressive
}
override fun getHit(pointsOfDamage: Int) {
// Same logic from before
}
override fun calmAgain() {
// Return to Still state
}
}
*/
Allow an object to alter its behavior at runtime.
enum class Direction {
LEFT, RIGHT
}
data class Projectile(
private var x: Int,
private var y: Int,
private var direction: Direction
)
object Weapons {
// Flies straight
fun peashooter(x: Int, y: Int, direction: Direction):
Projectile {
return Projectile(x, y, direction)
}
// Returns back after reaching end of the screen
fun banana(x: Int, y: Int, direction: Direction):
Projectile {
return Projectile(x, y, direction)
}
// Other similar implementations here
}
class OurHero {
private var direction = Direction.LEFT
private var x: Int = 42
private var y: Int = 173
var currentWeapon = Weapons::peashooter
val shoot = fun() {
currentWeapon(x, y, direction)
}
}
interface Weapon {
fun shoot(x: Int, y: Int, direction: Direction): Projectile
}
// Flies straight
class Peashooter : Weapon {
override fun shoot(
x: Int,
y: Int,
direction: Direction
) = Projectile(x, y, direction)
}
// Returns back after reaching end of the screen
class Banana : Weapon {
override fun shoot(
x: Int,
y: Int,
direction: Direction
) = Projectile(x, y, direction)
}
val hero = OurHero()
hero.shoot()
hero.currentWeapon = Weapons::banana
hero.shoot()
A class Derived
can implement an interface Base
by delegating all of its public members to a specified object:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}