Design Patterns and the happy dev friends

Design Patterns and the happy dev friends

This deck is a journey through the Design Patterns, used in a talk kept with Sebastiano Gottardo at Droidcon IT 2017

6923bdeb363961b064d2cdb6329982d6?s=128

Roberto Orgiu

April 06, 2017
Tweet

Transcript

  1. DESIGN PATTERNS AND THE HAPPY DEV FRIENDS

  2. A MOVIE BY US (THE GUYS ON THE STAGE)

  3. WHAT ARE THEY?

  4. WORKING SOLUTIONS TO COMMON PROBLEMS DESIGN PATTERNS ARE

  5. THEY JUST WORK™ Everyone that used them

  6. WHY SHOULD WE USE THEM?

  7. DESIGN PATTERNS AND THE HAPPY DEV FRIENDS WHY SHOULD WE

    USE THEM? ▸ Almost ready-to-use solutions ▸ Generic ▸ Increases decoupling ▸ Favors testing ▸ Android already uses a bunch of them
  8. CODE SAMPLES?

  9. CODE SAMPLES?

  10. CODE SAMPLES? WE LIKE THIS BETTER

  11. OBSERVER/ OBSERVABLE

  12. ANDROIDNE.WS Nope! Are there news?

  13. ANDROIDNE.WS

  14. ANDROIDNE.WS

  15. THERE MUST BE A BETTER WAY Someone who knew stuff

  16. ANDROIDNE.WS Sure, I’ll let you know when I have some!

    I’m interested in Android news
  17. ANDROIDNE.WS Hey, I have news! Oh-hi Android news! MOAR news!

    Such Androids!
  18. ANDROIDNE.WS Hey, I have news! Oh-hi Android news! MOAR news!

    Such Androids! I’m no longer interested!
  19. OBSERVER/OBSERVABLE OBSERVER interface Observer<T> { fun onDataChanged(data : T) }

    class SimpleObserver : Observer<Int> { override fun onDataChanged(data : Int) { … } }
  20. OBSERVER/OBSERVABLE OBSERVABLE interface Observable<T> { fun addObserver(observer : Observer<T>) }

    class SimpleObservable : Observable<T> { override fun addObserver(observer : Observer<T>) { observers.add(observer) } fun doThings() { val d = 3 observers.forEach { it.onDataChanged(d) } } }
  21. OBSERVER/OBSERVABLE HOW TO USE IT val observer1 = SimpleObserver() val

    observer2 = SimpleObserver() val observable = SimpleObservable() observable.addObserver(observer1) observable.addObserver(observer2) … observable.doThings()
  22. OBSERVER/OBSERVABLE WE ALREADY MET THIS PATTERN ▸ View.OnClickListener (& friends)

    ▸ Event bus ▸ RxJava
  23. STATIC FACTORY METHOD

  24. STATIC FACTORY METHOD FACTORY class Robot private constructor(private val serialNumber:

    Int) { companion object { var serialNumber: Int = 0 fun createRobot(): Robot = Robot(serialNumber++) } } // How to use it val someRobot = Robot.createRobot()
  25. STATIC FACTORY METHOD FACTORY class Robot private constructor(private val serialNumber:

    Int) { companion object { var serialNumber: Int = 0 fun createRobot(): Robot = Robot(serialNumber++) } } // How to use it val someRobot = Robot.createRobot()
  26. STATIC FACTORY METHOD FACTORY class Robot private constructor(private val serialNumber:

    Int) { companion object { var serialNumber: Int = 0 fun createRobot(): Robot = Robot(serialNumber++) } } // How to use it val someRobot = Robot.createRobot()
  27. STATIC FACTORY METHOD FACTORY class Robot private constructor(private val serialNumber:

    Int) { companion object { var serialNumber: Int = 0 fun createRobot(): Robot = Robot(serialNumber++) } } // How to use it val someRobot = Robot.createRobot()
  28. STATIC FACTORY METHOD FACTORY class Robot private constructor(private val serialNumber:

    Int) { companion object { var serialNumber: Int = 0 fun createRobot(): Robot = Robot(serialNumber++) } } // How to use it val someRobot = Robot.createRobot()
  29. STATIC FACTORY METHOD FACTORY class Robot private constructor(private val serialNumber:

    Int) { companion object { var serialNumber: Int = 0 fun createRobot(): Robot = Robot(serialNumber++) } } // How to use it val someRobot = Robot.createRobot()
  30. STATIC FACTORY ‣ Not really a pattern ‣ Controls the

    creation of objects ‣ Widely spread across Java/Android Calendar.getInstance() String.format() SomeFragment.newInstance() ಠ_ಠ
  31. FACTORY

  32. FACTORY PATTERN FACTORY interface Robot class Nestor4_Factory : RobotFactory {

    override fun createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } interface RobotFactory { fun createRobot(): Robot }
  33. FACTORY PATTERN FACTORY interface Robot class Nestor4_Factory : RobotFactory {

    override fun createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } interface RobotFactory { fun createRobot(): Robot }
  34. FACTORY PATTERN FACTORY interface Robot class Nestor4_Factory : RobotFactory {

    override fun createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } interface RobotFactory { fun createRobot(): Robot }
  35. FACTORY PATTERN FACTORY interface Robot class Nestor4_Factory : RobotFactory {

    override fun createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } interface RobotFactory { fun createRobot(): Robot }
  36. FACTORY PATTERN FACTORY interface Robot class Nestor4_Factory : RobotFactory {

    override fun createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } interface RobotFactory { fun createRobot(): Robot }
  37. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor4_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will produce a thousand robots usr.produceRobots(1000) }
  38. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor4_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will produce a thousand robots usr.produceRobots(1000) }
  39. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor4_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will produce a thousand robots usr.produceRobots(1000) }
  40. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor4_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will produce a thousand robots usr.produceRobots(1000) }
  41. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor4_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will produce a thousand robots usr.produceRobots(1000) }
  42. FACTORY PATTERN FACTORY interface Robot class Nestor4_Factory : RobotFactory {

    fun createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } interface RobotFactory { fun createRobot(): Robot }
  43. FACTORY PATTERN FACTORY class Nestor4_Factory : RobotFactory { fun createRobot():

    Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } class Nestor5_Factory : RobotFactory { fun createRobot(): Robot = Nestor5_Robot() private class Nestor5_Robot: Robot }
  44. FACTORY PATTERN FACTORY class Nestor4_Factory : RobotFactory { @Suppress(“unused”) fun

    createRobot(): Robot = Nestor4_Robot() private class Nestor4_Robot: Robot } class Nestor5_Factory : RobotFactory { fun createRobot(): Robot = Nestor5_Robot() private class Nestor5_Robot: Robot }
  45. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor4_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will produce a thousand robots usr.produceRobots(1000) }
  46. FACTORY PATTERN HOW TO USE IT // U.S. Robots and

    Mechanical Men class USR { private val factory : RobotFactory = Nestor5_Factory() fun produceRobots(quantity: Int): List<Robot> = List(quantity) { factory.createRobot() } } fun main(args: Array<String>) { val usr = USR() // will still produce a thousand robots usr.produceRobots(1000) }
  47. FACTORY ‣ Creational ‣ Decoupling ‣ Inheritance Define an interface

    for creating an object, but let the classes which implement the interface decide which class to instantiate.
  48. FACTORY ‣ Editable.Factory ‣ Context.getSystemService() ‣ LayoutInflater.Factory Define an interface

    for creating an object, but let the classes which implement the interface decide which class to instantiate.
  49. BUILDER

  50. BUILDER PATTERN INTERFACES // just a car interface Car //

    boost interface Boost object NOS: Boost // color of the exterior interface BodyColor object Orange: BodyColor object Blue: BodyColor // engine interface Engine object StockEngine: Engine object SuperPumpedEngine: Engine
  51. BUILDER PATTERN TARGET class QuarterMileCar private constructor( val boost: Boost?

    = null, val color: BodyColor = Orange, val engine: Engine = StockEngine ) : Car { // Builder goes here }
  52. BUILDER PATTERN TARGET class QuarterMileCar private constructor( val boost: Boost?

    = null, val color: BodyColor = Orange, val engine: Engine = StockEngine ) : Car { // Builder goes here }
  53. BUILDER PATTERN BUILDER class Builder { private var boost: Boost?

    = null private var color: BodyColor = Orange private var engine: Engine = StockEngine fun withBoost(boost: Boost): Builder { this.boost = boost return this } fun withColor(color: BodyColor): Builder { this.color = color return this } fun withEngine(engine: Engine): Builder { this.engine = engine return this } fun build(): QuarterMileCar = QuarterMileCar(boost, color, engine) }
  54. BUILDER PATTERN BUILDER class Builder { private var boost: Boost?

    = null private var color: BodyColor = Orange private var engine: Engine = StockEngine fun withBoost(boost: Boost): Builder { this.boost = boost return this } fun withColor(color: BodyColor): Builder { this.color = color return this } fun withEngine(engine: Engine): Builder { this.engine = engine return this } fun build(): QuarterMileCar = QuarterMileCar(boost, color, engine) }
  55. FACTORY PATTERN HOW TO USE IT fun main(args: Array<String>) {

    val supra = QuarterMileCar.Builder() .withBoost(NOS) .withColor(Orange) .withEngine(SuperPumpedEngine) .build() }
  56. FACTORY PATTERN HOW TO USE IT fun main(args: Array<String>) {

    val supra = QuarterMileCar.Builder() .withBoost(NOS) .withColor(Blue) .withEngine(SuperPumpedEngine) .build() }
  57. FACTORY PATTERN HOW TO USE IT fun main(args: Array<String>) {

    val s2000 = QuarterMileCar.Builder() .withEngine(SuperPumpedEngine) .build() }
  58. BUILDER PATTERN BUILDER class Builder { private var boost: Boost?

    = null private var color: BodyColor = Orange private var engine: Engine = StockEngine fun withBoost(boost: Boost): Builder { this.boost = boost return this } fun withColor(color: BodyColor): Builder { this.color = color return this } fun withEngine(engine: Engine): Builder { this.engine = engine return this } fun build(): QuarterMileCar = QuarterMileCar(boost, color, engine) }
  59. BUILDER PATTERN BUILDER <3 KOTLIN class QuarterMileCar private constructor( //

    constructor params ) : Car { class Builder { private var boost: Boost? = null private var color: BodyColor = Orange private var engine: Engine = StockEngine fun withBoost(boost: Boost) = apply { this.boost = boost } fun withColor(color: BodyColor) = apply { this.color = color } fun withEngine(engine: Engine) = apply { this.engine = engine } fun build() = QuarterMileCar(boost, color, engine) } }
  60. BUILDER ‣ Decoupling/Encapsulation ‣ Step-by-step control ‣ Immutability! The intent

    of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
  61. BUILDER ‣ [insert_library_from_Square_here] ‣ AlertDialog.Builder ‣ … The intent of

    the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
  62. CHAIN OF RESPONSIBILITY

  63. CHAIN OF RESPONSIBILITY when(x) {
 1 -> doThis()
 2 ->

    doThat()
 else -> crashPainfully()
 }
  64. CHAIN OF RESPONSIBILITY DRAWBACKS ▸ Execute more than one branch

    ▸ Testing ▸ Complex conditions ▸ Possible violation of SRP
  65. THE CHAIN OF RESPONSIBILITY AKA “SAVING THE DAY”

  66. CHAIN OF RESPONSIBILITY BASICS abstract class Base<T> {
 lateinit var

    next : Base<T>
 
 fun onEvent(data : T) {
 if (canManage(data)) {
 doManage(data)
 } else {
 next.onEvent(data)
 }
 }
 
 abstract fun canManage(data: T): Boolean
 abstract fun doManage(data: T)
 }
  67. CHAIN OF RESPONSIBILITY BASICS abstract class Base<T> {
 lateinit var

    next : Base<T>
 
 fun onEvent(data : T) {
 if (canManage(data)) {
 doManage(data)
 } else {
 next.onEvent(data)
 }
 }
 
 abstract fun canManage(data: T): Boolean
 abstract fun doManage(data: T)
 }
  68. CHAIN OF RESPONSIBILITY BASICS abstract class Base<T> {
 lateinit var

    next : Base<T>
 
 fun onEvent(data : T) {
 if (canManage(data)) {
 doManage(data)
 } else {
 next.onEvent(data)
 }
 }
 
 abstract fun canManage(data: T): Boolean
 abstract fun doManage(data: T)
 }
  69. CHAIN OF RESPONSIBILITY BASICS abstract class Base<T> {
 lateinit var

    next : Base<T>
 
 fun onEvent(data : T) {
 if (canManage(data)) {
 doManage(data)
 } else {
 next.onEvent(data)
 }
 }
 
 abstract fun canManage(data: T): Boolean
 abstract fun doManage(data: T)
 }
  70. CHAIN OF RESPONSIBILITY BASICS abstract class Base<T> {
 lateinit var

    next : Base<T>
 
 fun onEvent(data : T) {
 if (canManage(data)) {
 doManage(data)
 } else {
 next.onEvent(data)
 }
 }
 
 abstract fun canManage(data: T): Boolean
 abstract fun doManage(data: T)
 }
  71. CHAIN OF RESPONSIBILITY MAKING IT WORK class One : Base<Int>()

    { override fun canManage(data: Int) = data == 1 override fun doManage(data: Int) { // do amazing stuff here } }
  72. CHAIN OF RESPONSIBILITY MAKING IT WORK class One : Base<Int>()

    { override fun canManage(data: Int) = data == 1 override fun doManage(data: Int) { // do amazing stuff here } }
  73. CHAIN OF RESPONSIBILITY MAKING IT WORK class One : Base<Int>()

    { override fun canManage(data: Int) = data == 1 override fun doManage(data: Int) { // do amazing stuff here } }
  74. CHAIN OF RESPONSIBILITY MAKING IT WORK val chain = One()

    chain.next = Two()
  75. CHAIN OF RESPONSIBILITY MAKING IT WORK val chain = One()

    chain.next = Two() chain.onEvent(evt)
  76. CHAIN OF RESPONSIBILITY PROS ▸ Decouples senders and receivers ▸

    Simplifies the object ▸ Dynamically add & remove responsibilities
  77. ADAPTER

  78. USE A DESIGN EXPECTING ONE INTERFACE WITH A CLASS THAT

    IMPLEMENTS A DIFFERENT ONE ADAPTER
  79. ADAPTER LETS CLASSES WORK TOGETHER THAT COULDN’T OTHERWISE BECAUSE OF

    INCOMPATIBLE INTERFACES Someone who understood the previous slide ADAPTER
  80. ADAPTER existing object existing system adapter

  81. ADAPTER interface LegacySystem { fun accept(legacyData : LegacyData) } interface

    LegacyData { fun byteCount() : Long fun data() : String }
  82. ADAPTER interface LegacySystem { fun accept(legacyData : LegacyData) } interface

    LegacyData { fun byteCount() : Long fun data() : String } interface NewData { fun theData() : String }
  83. ADAPTER interface LegacySystem { fun accept(legacyData : LegacyData) } interface

    LegacyData { fun byteCount() : Long fun data() : String } interface NewData { fun theData() : String }
  84. ADAPTER class Adapter (val wrapped : NewData) : LegacyData {

    override fun byteCount() = wrapped.theData.bytes.length override fun data() = wrapped.theData }
  85. ADAPTER class Adapter (val wrapped : NewData) : LegacyData{ override

    fun byteCount() = wrapped.theData.bytes.length override fun data() = wrapped.theData }
  86. ADAPTER class Adapter (val wrapped : NewData) : LegacyData{ override

    fun byteCount() = wrapped.theData.bytes.length override fun data() = wrapped.theData }
  87. AND ON ANDROID?

  88. ADAPTER OUR DATASET RECYCLERVIEW

  89. ADAPTER OUR DATASET RECYCLERVIEW ADAPTER

  90. ADAPTER OUR DATASET RECYCLERVIEW (RECYCLERVIEW.)ADAPTER

  91. SOMETHING IS MISSING…

  92. FLYWEIGHT

  93. FLYWEIGHT SOMETHING ABOUT IT ▸ One instance to control them

    all ▸ Used when more instances can be controlled identically ▸ Single instances cannot be controlled independently
  94. WHERE HAVE WE SEEN THIS?

  95. VIEWHOLDER

  96. DECORATOR

  97. None
  98. DECORATOR BASE class Tony implements Hero { final int badassLevel;

    Tony(int badassLevel) { this.badassLevel = badassLevel; } @Override int badassLevel() { return badassLevel; } }
  99. DECORATOR BASE class Tony implements Hero { final int badassLevel;

    Tony(int badassLevel) { this.badassLevel = badassLevel; } @Override int badassLevel() { return badassLevel; } }
  100. DECORATOR BASE - Hero interface Hero { int badassLevel(); }

  101. DECORATOR DECORATOR class IronMan implements Hero { final Hero hero;

    IronMan(Hero hero) { this.hero = hero; } @Override int badassLevel() { return 2 * hero.badassLevel(); } }
  102. DECORATOR HOW TO USE IT Hero tony = new Tony(100);

    Hero ironMan = new IronMan(tony);
  103. IT’S NOT JUST THAT.

  104. None
  105. DECORATOR DECORATOR class HulkBuster implements Hero { final Hero hero;

    HulkSmasher(Hero hero) { this.hero = hero; } @Override int badassLevel() { return 3 * hero.badassLevel() + 1; } }
  106. DECORATOR HOW TO USE IT Hero tony = new Tony(100);

    Hero ironMan = new IronMan(tony); Hero hulkBuster = new HulkBuster(ironMan);
  107. DECORATOR HOW TO USE IT Hero tony = new Tony(100);

    Hero hulkBuster = new HulkBuster(tony);
  108. DECORATOR HOW TO USE IT Hero tony = new Tony(100);

    Hero hulkBuster = new HulkBuster(tony); Hero ironMan = new IronMan(hulkBuster);
  109. DECORATOR HOW TO USE IT Hero tony = new Tony(100);

    new IronMan(new HulkBuster(new IronMan(tony)));
  110. REPOSITORY

  111. REPOSITORY PATTERN

  112. REPOSITORY PATTERN REPOSITORY interface Repository<T> { fun add(item: T) fun

    add(items: List<T>) fun delete(item: T) fun update(item: T) fun query(specification: QuerySpec<T>): List<T> } interface QuerySpec<T> { fun getResults(items: List<T>): List<T> }
  113. REPOSITORY PATTERN REPOSITORY interface Repository<T> { fun add(item: T) fun

    add(items: List<T>) fun delete(item: T) fun update(item: T) fun query(specification: QuerySpec<T>): List<T> } interface QuerySpec<T> { fun getResults(items: List<T>): List<T> }
  114. REPOSITORY PATTERN REPOSITORY interface Repository<T> { fun add(item: T) fun

    add(items: List<T>) fun delete(item: T) fun update(item: T) fun query(specification: QuerySpec<T>): List<T> } interface QuerySpec<T> { fun getResults(items: List<T>): List<T> }
  115. REPOSITORY PATTERN REPOSITORY interface Repository<T> { fun add(item: T) fun

    add(items: List<T>) fun delete(item: T) fun update(item: T) fun query(specification: QuerySpec<T>): List<T> } interface QuerySpec<T> { fun getResults(items: List<T>): List<T> }
  116. REPOSITORY PATTERN MODEL data class Speaker( val id: Long, val

    name: String, val age: Int )
  117. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    list: MutableList<Speaker> = mutableListOf() override fun add(item: Speaker) { if (!list.contains(item)) { list.add(item) } } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { list.remove(item) } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>): List<Speaker> = specification.getResults(list) }
  118. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    list: MutableList<Speaker> = mutableListOf() override fun add(item: Speaker) { if (!list.contains(item)) { list.add(item) } } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { list.remove(item) } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>): List<Speaker> = specification.getResults(list) }
  119. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    list: MutableList<Speaker> = mutableListOf() override fun add(item: Speaker) { if (!list.contains(item)) { list.add(item) } } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { list.remove(item) } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>): List<Speaker> = specification.getResults(list) }
  120. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    list: MutableList<Speaker> = mutableListOf() override fun add(item: Speaker) { if (!list.contains(item)) { list.add(item) } } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { list.remove(item) } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>): List<Speaker> = specification.getResults(list) }
  121. REPOSITORY PATTERN QUERY object GetAllTheSebastianos : QuerySpec<Speaker> { override fun

    getResults(items: List<Speaker>): List<Speaker> = items.filter { it.name.startsWith("Sebastiano") } }
  122. REPOSITORY PATTERN QUERY object GetAllTheSebastianos : QuerySpec<Speaker> { override fun

    getResults(items: List<Speaker>): List<Speaker> = items.filter { it.name.startsWith("Sebastiano") } }
  123. REPOSITORY PATTERN QUERY object GetAllTheSebastianos : QuerySpec<Speaker> { override fun

    getResults(items: List<Speaker>): List<Speaker> = items.filter { it.name.startsWith("Sebastiano") } }
  124. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    list: MutableList<Speaker> = mutableListOf() override fun add(item: Speaker) { ... } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { ... } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>) { ... } }
  125. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    sharedPrefs: SharedPreference override fun add(item: Speaker) { ... } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { ... } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>) { ... } }
  126. REPOSITORY PATTERN MODEL class DroidconItSpeakers : Repository<Speaker> { private val

    database: SQLiteDatabase override fun add(item: Speaker) { ... } override fun add(items: List<Speaker>) { ... } override fun delete(item: Speaker) { ... } override fun update(item: Speaker) { ... } override fun query(specification: QuerySpec<Speaker>) { ... } }
  127. REPOSITORY ‣ Isolation ‣ Strong typing for reliability ‣ Testability

    The repository is a central place where data is stored and maintained.
  128. MORE INFO

  129. DESIGN PATTERNS HEAD FIRST

  130. DESIGN PATTERNS ELEMENTS OF REUSABLE OBJECT-ORIENTED SOFTWARE

  131. JAVA DESIGN PATTERNS CASTER.IO

  132. WE’RE HIRING!

  133. THANK YOU

  134. FACADE PATTERN

  135. SIMPLIFIES AN INTERFACE BY HIDING ALL THE COMPLEXITY BEHIND A

    CLEAN FACADE Someone who loves facades FACADE PATTERN
  136. FACADE I J A B C D E F G

    H
  137. FACADE I J A B C D E F G

    H FACADE
  138. FACADE HELPS DECOUPLING THE CLIENT FROM A SUBSYSTEM OF OTHER

    COMPONENTS FACADE
  139. FACADE VS ADAPTER both may wrap different classes

  140. FACADE VS ADAPTER both may wrap different classes simplify vs

    convert
  141. FACADE VS ADAPTER both may wrap different classes simplify vs

    convert PLUS easier and unified access to the subsystem