OO Patterns (Linn, 2014)

Functional Interface -> Named Function

State carrying functional i-face -> closures (a function and its context at the time of its definition)

public class ComposedComparator<T> implements Comparator<T> {
  private Comparator<T>[] comparators;
  public ComposedComparator(Comparator<T>... comparators) {
    this.comparators = comparators;
  }
  @Override
  public int compare(T o1, T o2) {
    //Iterate through comparators and call each in turn.
  }
}
def makeComposedComparison(comparisons: (Person, Person) => Int) = {
  (p1: Person, p2: Person) => comparisons.map(cmp => cmp(p1, p2)).find(_ != 0).getOrElse(0)
}
  def firstNameComparison(p1: Person, p2: Person) = p1.firstName.compareTo(p2.firstName)
  def lastNameComparison(p1: Person, p2: Person) = p1.lastName.compareTo(p2.lastName)
  val firstAndLastNameComparison = makeComposedComparison(firstNameComparison, lastNameComparison)
  val p1 = Person("John", "", "Adams")
  val p2 = Person("John", "Quincy", "Adams")
  firstAndLastNameComparison(p1, p2)

Command

Builder -> Immutable object

Iterator -> A sequence comprehension

Template

public abstract class TemplateExample{
  public void anOperation(){
    subOperationOne();
    subOperationTwo();
  }
  protected abstract void subOperationOne();
  protected abstract void subOperationTwo();
}
def makeAnOperation(subOperationOne: () => Unit, subOperationTwo: () => Unit) = () => {
  subOperationOne()
  subOperationTwo()
}

Strategy

Null object

Decorator or Wrapper

Visitor -> implicit conversion, or mix-inheritance/traits

DI

(Fatin, n.d.) Adapter Scala has built-in concept of interface adapters, expressed as implicit classes

Functional Patterns

Tail recursion

Not supported by JVM => Scala’s @tailrec, if the function is called recursively without being in the tail position, the compiler will generate an error.

Mutual recursion (trampoline)

Not supported by JVM => Scala’s support for trampolining hides a lot of the details of this and provides us with both a tailcall() method to make mutually recursive calls and a done() method to call when we’re done with the recursion.

def isOdd(n: Long): Boolean = if (n == 0) false else isEven(n - 1)
def isEven(n: Long): Boolean = if (n == 0) true else isOdd(n - 1)
// usage
isOdd(1001) // res3: Boolean = true
isOdd(100001) // java.lang.StackOverflowError
//
def isOddTrampoline(n: Long): TailRec[Boolean] = if (n == 0) done(false) else tailcall(isEvenTrampoline(n - 1))
def isEvenTrampoline(n: Long): TailRec[Boolean] = if (n == 0) done(true) else tailcall(isOddTrampoline(n - 1))
// usage
isOddTrampoline(100001).result // res4: Boolean = true, but it is O(n) (linear)

Filter-Map-Reduce

Chain of operations

Function Builder

Memoisation

Lazy sequence - Scala’s has built-in support for Lazy Sequence in its Stream library

Focused mutabilty - Good for holding a collection for indexing as it is faster than with immutable objects

References

  • Fatin, P. Design Patterns in Scala. Retrieved January 21, 2021, from https://pavelfatin.com/design-patterns-in-scala/
  • Linn, M. (2014). Functional programming patterns in Scala and Clojure. Pragmatic Programmers.