Slide 1

Slide 1 text

Gang of Four Patterns in Kotlin Lovis Möller @lovisbrot [email protected]

Slide 2

Slide 2 text

1994 C++ Program to an interface Composition over inheritance Patterns define a Language

Slide 3

Slide 3 text

Patterns

Slide 4

Slide 4 text

Patterns Structural Creational Behavioral Adapter Bridge Decorator Façade Flyweight Composite Proxy Factory method Abstract factory Singleton Builder Prototype Interpreter Template method Observer Visitor Iterator Command Memento Strategy Mediator State Chain of responsibility

Slide 5

Slide 5 text

Patterns Structural Creational Behavioral Adapter Bridge Decorator Façade Flyweight Composite Proxy Factory method Abstract factory Singleton Builder Prototype Interpreter Template method Observer Visitor Iterator Command Memento Strategy Mediator State Chain of responsibility

Slide 6

Slide 6 text

Strategy Define a family of algorithms, encapsulate each one, and make them interchangeable

Slide 7

Slide 7 text

interface Discount { double discountedPrice(double raw); }

Slide 8

Slide 8 text

interface Discount { double discountedPrice(double raw); } public static class Customer { final String name; final double fee; final Discount discount; public Customer(String name, double fee, Discount discount) { this.name = name; this.fee = fee; this.discount = discount; } public double pricePerMonth() { return discount.discountedPrice(fee); } }

Slide 9

Slide 9 text

interface Discount { double discountedPrice(double raw); } public static class Customer { final String name; final double fee; final Discount discount; public Customer(String name, double fee, Discount discount) { this.name = name; this.fee = fee; this.discount = discount; } public double pricePerMonth() { return discount.discountedPrice(fee); } }

Slide 10

Slide 10 text

interface Discount { double discountedPrice(double raw); } public static class Customer { final String name; final double fee; final Discount discount; public Customer(String name, double fee, Discount discount) { this.name = name; this.fee = fee; this.discount = discount; } public double pricePerMonth() { return discount.discountedPrice(fee); } }

Slide 11

Slide 11 text

interface Discount { double discountedPrice(double raw); } public static class NoDiscount implements Discount { @Override public double discountedPrice(double raw) { return raw; } }

Slide 12

Slide 12 text

interface Discount { double discountedPrice(double raw); } public static class NoDiscount implements Discount { @Override public double discountedPrice(double raw) { return raw; } } public static class StudentDiscount implements Discount { @Override public double discountedPrice(double raw) { return 0.5 * raw; } }

Slide 13

Slide 13 text

Customer student = new Customer("Ned", 10, new StudentDiscount()); Customer regular = new Customer("John", 10, new NoDiscount()); System.out.println(String.format("%s pays %.2f per month", student.name, student.pricePerMonth())); System.out.println(String.format("%s pays %.2f per month", regular.name, regular.pricePerMonth()));

Slide 14

Slide 14 text

Customer student = new Customer("Ned", 10, new StudentDiscount()); Customer regular = new Customer("John", 10, new NoDiscount()); System.out.println(String.format("%s pays %.2f per month", student.name, student.pricePerMonth())); System.out.println(String.format("%s pays %.2f per month", regular.name, regular.pricePerMonth()));

Slide 15

Slide 15 text

Customer student = new Customer("Ned", 10, new StudentDiscount()); Customer regular = new Customer("John", 10, new NoDiscount()); System.out.println(String.format("%s pays %.2f per month", student.name, student.pricePerMonth())); System.out.println(String.format("%s pays %.2f per month", regular.name, regular.pricePerMonth()));

Slide 16

Slide 16 text

typealias Discount = (Double)  Double

Slide 17

Slide 17 text

typealias Discount = (Double)  Double class Customer(val name: String, val fee: Double, val discount: Discount) { fun pricePerMonth() = discount(fee) }

Slide 18

Slide 18 text

typealias Discount = (Double)  Double class Customer(val name: String, val fee: Double, val discount: Discount) { fun pricePerMonth() = discount(fee) } val studentDiscount = { raw: Double  raw/2 } val noDiscount = { raw: Double  raw }

Slide 19

Slide 19 text

typealias Discount = (Double)  Double class Customer(val name: String, val fee: Double, val discount: Discount) { fun pricePerMonth() = discount(fee) } val studentDiscount = { raw: Double  raw/2 } val noDiscount = { raw: Double  raw } val student = Customer("Ned", 10.0, studentDiscount) val regular = Customer("John", 10.0, noDiscount) println("${student.name} pays %.2f per month".format(student.pricePerMonth())) println("${regular.name} pays %.2f per month".format(regular.pricePerMonth()))

Slide 20

Slide 20 text

typealias Discount = (Double)  Double class Customer(val name: String, val fee: Double, val discount: Discount) { fun pricePerMonth() = discount(fee) } val studentDiscount = { raw: Double  raw/2 } val noDiscount = { raw: Double  raw } val student = Customer("Ned", 10.0, studentDiscount) val regular = Customer("John", 10.0, noDiscount) println("${student.name} pays %.2f per month".format(student.pricePerMonth())) println("${regular.name} pays %.2f per month".format(regular.pricePerMonth()))

Slide 21

Slide 21 text

typealias Discount = (Double)  Double class Customer(val name: String, val fee: Double, val discount: Discount) { fun pricePerMonth() = discount(fee) } val studentDiscount = { raw: Double  raw/2 } val noDiscount = { raw: Double  raw } val student = Customer("Ned", 10.0, studentDiscount) val regular = Customer("John", 10.0, noDiscount) println("${student.name} pays %.2f per month".format(student.pricePerMonth())) println("${regular.name} pays %.2f per month".format(regular.pricePerMonth()))

Slide 22

Slide 22 text

Builder Separate the construction of a complex object from its representation so that the same construction process can create different representations

Slide 23

Slide 23 text

public interface CarBuilder { void setDoors(int doors); void setColor(String color); Car build(); } public static CarBuilder newBuilder(){ … }

Slide 24

Slide 24 text

public interface CarBuilder { void setDoors(int doors); void setColor(String color); Car build(); } public final class Car { private int doors; private String color; public Car(int doors, String color) { this.doors = doors; this.color = color; } } public static CarBuilder newBuilder(){ … }

Slide 25

Slide 25 text

CarBuilder builder = Car.newBuilder(); builder.setColor("green"); builder.setDoors(5); Car car = builder.build(); // 

Slide 26

Slide 26 text

class Car(var color: String = “red”, var doors = 3, )

Slide 27

Slide 27 text

class Car(var color: String = “red”, var doors = 3, ) val car = Car( color = “green”, doors = 5,  )

Slide 28

Slide 28 text

class Car() { var color: String = "red" var doors = 3 }

Slide 29

Slide 29 text

val car = Car().apply { color = "yellow" doors = 5 } class Car() { var color: String = "red" var doors = 3 }

Slide 30

Slide 30 text

class Car() { var color: String = "red" var doors = 3 } val config: Car.()  Unit = { color = "yellow" doors = 5 }

Slide 31

Slide 31 text

class Car() { var color: String = "red" var doors = 3 } val config: Car.()  Unit = { color = "yellow" doors = 5 } val car = Car().apply(config)

Slide 32

Slide 32 text

class Car() { var color: String = "red" var doors = 3 } val config: Car.()  Unit = { color = "yellow" doors = 5 } val car = Car() .apply(COBALT_BLUE) .apply(LEATHER_PACKAGE) .apply(TIRES_18_INCH)

Slide 33

Slide 33 text

Singleton Ensure a class only has one instance, and provide a global point of access to it

Slide 34

Slide 34 text

public class Dictionary { private static final Dictionary INSTANCE = new Dictionary(); private Dictionary() { … } public static Dictionary get() { return INSTANCE; } public void addWord(String word, String definition){ … } public String getDefinition(String word) { … } }

Slide 35

Slide 35 text

public class Dictionary { private static final Dictionary INSTANCE = new Dictionary(); private Dictionary() { … } public static Dictionary get() { return INSTANCE; } public void addWord(String word, String definition){ … } public String getDefinition(String word) { … } }

Slide 36

Slide 36 text

public class Dictionary { private static final Dictionary INSTANCE = new Dictionary(); private Dictionary() { … } public static Dictionary get() { return INSTANCE; } public void addWord(String word, String definition){ … } public String getDefinition(String word) { … } }

Slide 37

Slide 37 text

public class Dictionary { private static final Dictionary INSTANCE = new Dictionary(); private Dictionary() { … } public static Dictionary get() { return INSTANCE; } public void addWord(String word, String definition){ … } public String getDefinition(String word) { … } }

Slide 38

Slide 38 text

object Dictionary { fun addWord(word: String, definition: String) { … } fun getDefinition(word: String): String { … } }

Slide 39

Slide 39 text

Prototype Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype

Slide 40

Slide 40 text

/** * A class implements the Cloneable interface to * indicate to the {@link java.lang.Object#clone()} method that it * is legal for that method to make a * field-for-field copy of instances of that class. *

* Invoking Object's clone method on an instance that does not implement the * Cloneable interface results in the exception * CloneNotSupportedException being thrown. *

* By convention, classes that implement this interface should override * Object.clone (which is protected) with a public method. * See {@link java.lang.Object#clone()} for details on overriding this * method. *

* Note that this interface does not contain the clone method. * Therefore, it is not possible to clone an object merely by virtue of the * fact that it implements this interface. Even if the clone method is invoked * reflectively, there is no guarantee that it will succeed. * */ public interface Cloneable { }

Slide 41

Slide 41 text

/** * A class implements the Cloneable interface to * indicate to the {@link java.lang.Object#clone()} method that it * is legal for that method to make a * field-for-field copy of instances of that class. *

* Invoking Object's clone method on an instance that does not implement the * Cloneable interface results in the exception * CloneNotSupportedException being thrown. *

* By convention, classes that implement this interface should override * Object.clone (which is protected) with a public method. * See {@link java.lang.Object#clone()} for details on overriding this * method. *

* Note that this interface does not contain the clone method. * Therefore, it is not possible to clone an object merely by virtue of the * fact that it implements this interface. Even if the clone method is invoked * reflectively, there is no guarantee that it will succeed. * */ public interface Cloneable { } Clone is broken
 http://www.artima.com/intv/bloch13.html

Slide 42

Slide 42 text

data class EMail( var recipient: String, var subject: String?, var message: String? )

Slide 43

Slide 43 text

data class EMail( var recipient: String, var subject: String?, var message: String? )

Slide 44

Slide 44 text

data class EMail( var recipient: String, var subject: String?, var message: String? ) val mail = EMail("[email protected]", "Hello", "Don't know what to write.")

Slide 45

Slide 45 text

data class EMail( var recipient: String, var subject: String?, var message: String? ) val mail = EMail("[email protected]", "Hello", "Don't know what to write.") val copy1 = mail.copy(recipient = "[email protected]")

Slide 46

Slide 46 text

data class EMail( var recipient: String, var subject: String?, var message: String? ) val mail = EMail("[email protected]", "Hello", "Don't know what to write.") val copy1 = mail.copy(recipient = "[email protected]") val copy2 = mail.copy(recipient = "[email protected]", subject = "Re: Hello")

Slide 47

Slide 47 text

data class EMail( var recipient: String, var subject: String?, var message: String? ) val mail = EMail("[email protected]", "Hello", "Don't know what to write.") val copy1 = mail.copy(recipient = "[email protected]") val copy2 = mail.copy(recipient = "[email protected]", subject = "Re: Hello") val copy3 = mail.copy()

Slide 48

Slide 48 text

Iterator Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Slide 49

Slide 49 text

public class Sentence { private final List words; public Sentence(List words) { this.words = words; } public List getWords() { return words; } }

Slide 50

Slide 50 text

public class Sentence { private final List words; public Sentence(List words) { this.words = words; } public List getWords() { return words; } } Sentence sentence = new Sentence(words); for (String word : sentence.getWords()) { // }

Slide 51

Slide 51 text

public class Sentence { private final List words; public Sentence(List words) { this.words = words; } public List getWords() { return words; } } Sentence sentence = new Sentence(words); for (String word : sentence.getWords()) { //not so cool }

Slide 52

Slide 52 text

public static class Sentence { … } public class IterableSentence extends Sentence implements Iterable { public IterableSentence(List words) { super(words); } @Override public Iterator iterator() { return getWords().iterator(); } }

Slide 53

Slide 53 text

public static class Sentence { … } public class IterableSentence extends Sentence implements Iterable { public IterableSentence(List words) { super(words); } @Override public Iterator iterator() { return getWords().iterator(); } } Sentence sentence = new IterableSentence(words);
 for (String word : sentence) { //better }

Slide 54

Slide 54 text

class Sentence(val words: List)

Slide 55

Slide 55 text

class Sentence(val words: List) operator fun Sentence.iterator(): Iterator = words.iterator()

Slide 56

Slide 56 text

class Sentence(val words: List) operator fun Sentence.iterator(): Iterator = words.iterator()

Slide 57

Slide 57 text

class Sentence(val words: List) operator fun Sentence.iterator(): Iterator = words.iterator()

Slide 58

Slide 58 text

class Sentence(val words: List) operator fun Sentence.iterator(): Iterator = words.iterator()

Slide 59

Slide 59 text

class Sentence(val words: List) operator fun Sentence.iterator(): Iterator = words.iterator() val sentence = Sentence(words) for(word in sentence){ }

Slide 60

Slide 60 text

class OtherSentence( private val words: List ): Iterable by words

Slide 61

Slide 61 text

class OtherSentence( private val words: List ): Iterable by words

Slide 62

Slide 62 text

class OtherSentence( private val words: List ): Iterable by words

Slide 63

Slide 63 text

class OtherSentence( private val words: List ): Iterable by words val otherSentence = OtherSentence(words) for(word in otherSentence){ … }

Slide 64

Slide 64 text

class OtherSentence( private val words: List ): Iterable by words val otherSentence = OtherSentence(words) for(word in otherSentence){ … } otherSentence.forEach { word  … } if(otherSentence.contains(“X-Mas”)){ … }

Slide 65

Slide 65 text

Visitor Represent an operation to be performed on the elements of an object structure. A Visitor lets you define a new operation without changing the classes of the elements on which it operates

Slide 66

Slide 66 text

interface Shape { T accept(ShapeVisitor visitor); } public static class Square implements Shape { final double side; public Square(double side) { this.side = side; } @Override public T accept(ShapeVisitor visitor) { return visitor.visit(this); } } public static class Circle implements Shape { final double radius; public Circle(double radius) { this.radius = radius; } @Override public T accept(ShapeVisitor visitor) { return visitor.visit(this); } } public static class Rectangle implements Shape { final double width; final double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public T accept(ShapeVisitor visitor) { return visitor.visit(this); } } interface ShapeVisitor { T visit(Square element); T visit(Circle element); T visit(Rectangle element); } public static class AreaVisitor implements ShapeVisitor { public Double visit(Square element) { return element.side * element.side; } public Double visit(Circle element) { return Math.PI * element.radius * element.radius; } public Double visit(Rectangle element) { return element.height * element.width; } } public static class PerimeterVisitor implements ShapeVisitor { public Double visit(Square element) { return 4 * element.side; } public Double visit(Circle element) { return 2 * Math.PI * element.radius; } public Double visit(Rectangle element) { return (2 * element.height + 2 * element.width); } }

Slide 67

Slide 67 text

interface Shape { T accept(ShapeVisitor visitor); } public static class Square implements Shape { final double side; public Square(double side) { this.side = side; } @Override public T accept(ShapeVisitor visitor) { return visitor.visit(this); } } public static class Circle implements Shape { final double radius; public Circle(double radius) { this.radius = radius; } @Override public T accept(ShapeVisitor visitor) { return visitor.visit(this); } } public static class Rectangle implements Shape { final double width; final double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public T accept(ShapeVisitor visitor) { return visitor.visit(this); } } interface ShapeVisitor { T visit(Square element); T visit(Circle element); T visit(Rectangle element); } public static class AreaVisitor implements ShapeVisitor { public Double visit(Square element) { return element.side * element.side; } public Double visit(Circle element) { return Math.PI * element.radius * element.radius; } public Double visit(Rectangle element) { return element.height * element.width; } } public static class PerimeterVisitor implements ShapeVisitor { public Double visit(Square element) { return 4 * element.side; } public Double visit(Circle element) { return 2 * Math.PI * element.radius; } public Double visit(Rectangle element) { return (2 * element.height + 2 * element.width); } } “Elements” “Visitors”

Slide 68

Slide 68 text

sealed class Shape() class Square(val side: Double) : Shape() class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape()

Slide 69

Slide 69 text

sealed class Shape() class Square(val side: Double) : Shape() class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape() val perimeterVisitor = { shape: Shape  when (shape) { is Rectangle  2 * shape.height + 2 * shape.width is Circle  2 * Math.PI * shape.radius is Square  4 * shape.side } }

Slide 70

Slide 70 text

sealed class Shape() class Square(val side: Double) : Shape() class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape() val perimeterVisitor = { shape: Shape  when (shape) { is Rectangle  2 * shape.height + 2 * shape.width is Circle  2 * Math.PI * shape.radius is Square  4 * shape.side } } val figures = listOf(Circle(4.0), Square(5.0), Rectangle(6.0, 7.0)) val totalArea = figures.sumByDouble { perimeterVisitor(it) }

Slide 71

Slide 71 text

sealed class Shape() class Square(val side: Double) : Shape() class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape() val perimeterVisitor = { shape: Shape  when (shape) { is Rectangle  2 * shape.height + 2 * shape.width is Circle  2 * Math.PI * shape.radius else  } } val figures = listOf(Circle(4.0), Square(5.0), Rectangle(6.0, 7.0)) val totalArea = figures.sumByDouble { perimeterVisitor(it) }

Slide 72

Slide 72 text

sealed class Shape() class Square(val side: Double) : Shape() class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape() val perimeterVisitor = { shape: Shape  when (shape) { is Rectangle  2 * shape.height + 2 * shape.width is Circle  2 * Math.PI * shape.radius } } val figures = listOf(Circle(4.0), Square(5.0), Rectangle(6.0, 7.0)) val totalArea = figures.sumByDouble { perimeterVisitor(it) } ‘when’ expression must be exhaustive

Slide 73

Slide 73 text

sealed class Shape() class Square(val side: Double) : Shape() class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape() val perimeterVisitor = { shape: Shape  when (shape) { is Rectangle  2 * shape.height + 2 * shape.width is Circle  2 * Math.PI * shape.radius is Square  4 * shape.side } } val figures = listOf(Circle(4.0), Square(5.0), Rectangle(6.0, 7.0)) val totalArea = figures.sumByDouble { perimeterVisitor(it) }

Slide 74

Slide 74 text

Decorator Attach additional responsibilities to an object dynamically

Slide 75

Slide 75 text

public interface Text { void draw(); }

Slide 76

Slide 76 text

public interface Text { void draw(); } public class PrintedText implements Text { … }

Slide 77

Slide 77 text

public interface Text { void draw(); } public class PrintedText implements Text { … } public abstract class TextEffect implements Text { protected Text decorated; … }

Slide 78

Slide 78 text

public interface Text { void draw(); } public class PrintedText implements Text { … } public abstract class TextEffect implements Text { protected Text decorated; … } public class Background extends TextEffect { public Background(Text decorated) { super(decorated); } @Override public void draw() { … decorated.draw(); } … }

Slide 79

Slide 79 text

public interface Text { void draw(); } public class PrintedText implements Text { … } public abstract class TextEffect implements Text { protected Text decorated; … } public class Background extends TextEffect { public Background(Text decorated) { super(decorated); } @Override public void draw() { … decorated.draw(); } … }

Slide 80

Slide 80 text

new Background(
 new PrintedText("With Background")
 ).draw();

Slide 81

Slide 81 text

new Background(
 new PrintedText("With Background")
 ).draw(); new Background( new Underline( new PrintedText(“Underlined with Background”) ) ).draw();

Slide 82

Slide 82 text

new Background(
 new PrintedText("With Background")
 ).draw(); new Background( new Underline( new PrintedText(“Underlined with Background”) ) ).draw(); new Background( new Underline( new Blinking( new PrintedText(“Underlined with Background, that blinks!”) ) ) ).draw();

Slide 83

Slide 83 text

interface Text { fun draw() } class DefaultText(val text: String) : Text { override fun draw() { … } }

Slide 84

Slide 84 text

interface Text { fun draw() } class DefaultText(val text: String) : Text { override fun draw() { … } } fun Text.underline(decorated: Text.()  Unit) { … this.decorated() … }

Slide 85

Slide 85 text

interface Text { fun draw() } class DefaultText(val text: String) : Text { override fun draw() { … } } fun Text.underline(decorated: Text.()  Unit) { … this.decorated() … }

Slide 86

Slide 86 text

interface Text { fun draw() } class DefaultText(val text: String) : Text { override fun draw() { … } } fun Text.underline(decorated: Text.()  Unit) { … this.decorated() … }

Slide 87

Slide 87 text

interface Text { fun draw() } class DefaultText(val text: String) : Text { override fun draw() { … } } fun Text.underline(decorated: Text.()  Unit) { //decorate this.decorated() //decorate }

Slide 88

Slide 88 text

interface Text { fun draw() } class DefaultText(val text: String) : Text { override fun draw() { … } } fun Text.underline(decorated: Text.()  Unit) { //decorate this.decorated() //decorate } fun Text.background(decorated: Text.()  Unit) { //decorate this.decorated() //decorate }

Slide 89

Slide 89 text

with(DefaultText("Hello")) { background { underline { draw() } } }

Slide 90

Slide 90 text

Decorator…? The Decorator pattern as demonstrated in GoF is just a very convoluted way to achieve functions composition. 
 ~ Mario Fusco

Slide 91

Slide 91 text

Function composition f(x) g(x) …made simple! (But probably not really correct. Sorry, not sorry, mathematicians )

Slide 92

Slide 92 text

Function composition f(x) g(x) h(x) = (f ∘ g)(x)
 …made simple! (But probably not really correct. Sorry, not sorry, mathematicians )

Slide 93

Slide 93 text

Function composition f(x) g(x) h(x) = (f ∘ g)(x)
 = g(f(x)) …made simple! (But probably not really correct. Sorry, not sorry, mathematicians )

Slide 94

Slide 94 text

Function composition f(x) = x + 1 g(x) = x2 h(x) = (f ∘ g)(x)
 = g(f(x)) = (x + 1)2 …made simple! (But probably not really correct. Sorry, not sorry, mathematicians )

Slide 95

Slide 95 text

Function composition f(x) = x + 1 g(x) = x2 h(x) = (f ∘ g)(x)
 = g(f(x)) = (x + 1)2 …made simple! (But probably not really correct. Sorry, not sorry, mathematicians ) fun h(x: Int) = g(f(x))


Slide 96

Slide 96 text

fun underline(text: String) = … fun background(text: String) = …

Slide 97

Slide 97 text

fun underline(text: String) = … fun background(text: String) = … val text = underline(background(“Functional?”))

Slide 98

Slide 98 text

fun underline(text: String): String = … fun background(text: String): String = … val text = underline(background(“Functional?”))

Slide 99

Slide 99 text

fun underline(text: String): String = … fun background(text: String): String = … val text: String = underline(background(“Functional?”))

Slide 100

Slide 100 text

fun underline(text: String): String = … fun background(text: String): String = … val text: String = underline(background(“Functional?”))

Slide 101

Slide 101 text

fun underline(text: String): String = … fun background(text: String): String = …

Slide 102

Slide 102 text

fun underline(text: String): String = … fun background(text: String): String = … fun combine( ):  { return  }

Slide 103

Slide 103 text

fun underline(text: String): String = … fun background(text: String): String = … fun combine(f: (String)  String, g: (String)  String):  { return  }

Slide 104

Slide 104 text

fun underline(text: String): String = … fun background(text: String): String = … fun combine(f: (String)  String, g: (String)  String):  { return { x  g(f(x)) } }

Slide 105

Slide 105 text

fun underline(text: String): String = … fun background(text: String): String = … fun combine(f: (String)  String, g: (String)  String): (String)  String { return { x  g(f(x)) } }

Slide 106

Slide 106 text

fun underline(text: String): String = … fun background(text: String): String = … fun combine(f: (String)  String, g: (String)  String): (String)  String { return { x  g(f(x)) } } val h = combine( underline, background) val text = h(“Functional?”)

Slide 107

Slide 107 text

fun underline(text: String): String = … fun background(text: String): String = … fun combine(f: (String)  String, g: (String)  String): (String)  String { return { x  g(f(x)) } }

Slide 108

Slide 108 text

fun underline(text: String): String = … fun background(text: String): String = … fun ((String)  String).combine(g: (String)  String): (String)  String { return { x  g(this(x)) } }

Slide 109

Slide 109 text

fun underline(text: String): String = … fun background(text: String): String = … fun ((String)  String).combine(g: (String)  String): (String)  String { return { x  g(this(x)) } } val h = underline.combine( background)

Slide 110

Slide 110 text

fun underline(text: String): String = … fun background(text: String): String = … infix fun ((String)  String).then(g: (String)  String): (String)  String { return { x  g(this(x)) } } val h = underline.combine( background)

Slide 111

Slide 111 text

fun underline(text: String): String = … fun background(text: String): String = … infix fun ((String)  String).then(g: (String)  String): (String)  String { return { x  g(this(x)) } } val h = underline combine background

Slide 112

Slide 112 text

fun underline(text: String): String = … fun background(text: String): String = … infix fun ((String)  String).then(g: (String)  String): (String)  String { return { x  g(this(x)) } } val h = underline combine background val decoratedText = h(“Functional!?”)

Slide 113

Slide 113 text

infix fun ((P1)  IP).combine(f: (IP)  R): (P1)  R { return { p1: P1  f(this(p1)) } }

Slide 114

Slide 114 text

infix fun ((P1)  IP).combine(f: (IP)  R): (P1)  R { return { p1: P1  f(this(p1)) } }

Slide 115

Slide 115 text

Lovis Möller @lovisbrot [email protected] https://dev.to/lovis/gang-of-four-patterns-in-kotlin https://dev.to/lovis/gang-of-four-patterns-in-kotlin---slight-return https://github.com/lmller/gof-in-kotlin