Pimp My Scala – Effektive Scala Nutzung
durch typische Entwurfsmuster
OOP 2012
Andreas Tönne, NovaTec GmbH
Direktor R&D der NovaTec GmbH
Standort Frankfurt am Main
© NovaTec
12.06.2013
2
Übersicht
Blitzkurs Scala
Einführung in typische Scala Pattern
 Basierend auf ausgewählten Schlüsselfeatures von Scala
 Beispiele für idiomatisch korrekte Pattern
 Einschließlich Pimp My Library, Cake und Type Classes
Implementierungsskizzen und Erläuterungen
Umfangreiche Beschreibungen und Codebeispiele unter
scala.novatec-gmbh.de
© NovaTec
12.06.2013
3
Design Pattern
Wir alle wissen was Pattern sind?
GoF: Gamma, Helm, Johnson, Vlissides: „Entwurfsmuster“ (Addison-Wesley, 1996)
Pattern sind keine Erfindung sondern einer Entdeckung!
„Keines der Entwurfsmuster … beschreibt neuartige Entwürfe. (…) Trotzdem wurden viele
dieser Entwürfe noch nie dokumentiert. Sie gehören entweder zum Allgemeinwissen …
oder sie sind Teil erfolgreicher … Systeme.“
„Die Entwurfsmuster … sind Beschreibungen zusammenarbeitender Objekte und Klassen,
die maßgeschneidert sind, um ein allgemeines Entwurfsproblem in einem bestimmten
Kontext zu lösen.“
© NovaTec
12.06.2013
4
Design Pattern
Design Pattern entstehen im Kontext der Möglichkeiten einer Programmiersprache
Umgehen unerwünschte Eigenarten der Sprache
Bilden zusammengesetzte wünschenswerte neue Sprachkonstrukte
Dokumentieren idiomatisch guten Einsatz der Sprache
Welche GoF Pattern „passen“ zu Scala?
 Manche Pattern werden „unsichtbar“ durch Scala Sprachmittel ausdrückbar
 Manche Pattern werden zu Anti-Pattern da man das Ursprungsproblem in Scala anders löst
© NovaTec
12.06.2013
5
GoF Pattern – Bewertung für Scala
Unsichtbare Pattern
 Besucher, Brücke, Iterator, Prototyp, Singleton, Strategie
Vereinfachte Pattern
 Abstrakte Fabrik, Beobachter, Dekorierer, Fabrik, Interpreter, Proxy, Zustand,
Zuständigkeitskette
Anti-Pattern
 Befehl, Schablonenmethode
Sonstige Pattern
 Adapter, Erbauer, Fassade, Fliegengewicht, Kompositum, Memento, Vermittler
Ohne Nachweis im Einzelnen!
© NovaTec
12.06.2013
6
Es lohnt sich in Scala nach Quellen neuer Pattern zu suchen
© NovaTec
12.06.2013
7
Grundlagen neuer Scala Pattern
Jedes neue Scala Feature kann Basis neuer Pattern sein
 Komplexe Designs kompakter als Pattern beschreibbar (anstelle eines Frameworks)
 Höherwertige Abstraktionen über der Programmstruktur und Typen erlauben neuartige
Compilezeit Pattern
Scala läuft auf der JVM aber …
 Nicht alle Pattern können 1-1 nach Java übersetzt werden
 Bsp. Cake-Pattern bringt seinen Nutzen zur Compilezeit
 Nicht übersetzbar: Ausnutzen von Modulstruktur und besserem Typsystem
© NovaTec
12.06.2013
8
Scala Blitzkurs
© NovaTec
12.06.2013
9
Scala Motivation
Scala = Scalable Language
Eine Sprache für viele Aufgaben anstelle vieler Sprachen für jeweils eine Aufgabe
Skalierung nach Problemgröße
 Geeignet für kleine Anwendungen (Scripte)
•
Wichtig: Kompaktheit, Schnelligkeit der Entwicklung, Leicht Anpassbarkeit
 Geeignet für große Anwendungen
•
Wichtig: Modularisierung
Skalierung nach Komplexität
 Kontrolle der Komplexität über neue Frameworks, neue Typen und Kontrollstrukturen und
eingebettete DSLs
© NovaTec
12.06.2013
10
Scala Motivation Forts.
Scala kompiliert nach Java Bytecode
Nutzt die JVM und alle darauf bestehenden Tools und Frameworks
Scala = Java + Viel Gutes aus der Theorie der Programmiersprachen
 Kompakterer Code (Typ Inferenz, viele Automatismen statt Boilerplate Code)
 Saubere Integration von Funktionaler Programmierung (Lambda, Closure, Pattern Matching)
 Traits anstelle von Interfaces
 Leistungsfähiges Typsystem
 Modulsystem eingebaut (Trait, Mixin, Abstrakte Member, selftype, Typparameter)
 Voll Interoperabel mit Java
 Geschwindigkeit vergleichbar mit Java
© NovaTec
12.06.2013
11
Scala Tools
scala
 Repl für interaktive Ausführung
 Ausführung von Scala Scripten
 Es gibt wenig was man nicht vollständig in der Repl ausführen kann
scalac
 Kompiliert .scala-Dateien in eine oder mehrere .class-Dateien
 Scala-Dateien Unterschied zu Java:
•
Kein Zwang Klasse = Datei
•
Keine Package-gesteuerte Unterverzeichnisse
•
Scala-Datei ~ Transcript der Repl
– Sequenz von Ausdrücken und Definitionen
© NovaTec
12.06.2013
12
Scala Blitzbeispiel - Kompaktheit
class MyClass {
private int index;
private String name;
private final int id;
}
public MyClass(int index, String name) {
this.index = index;
this.name = name;
}
// getter und setter für index
// getter für name
class MyClass(var index: Int, val name: String, id:Int)
© NovaTec
12.06.2013
13
Scala Blitzbeispiel - Erweiterbarkeit
public BigInteger factorial(BitInteger x)
{
BigInteger fact;
if (x == BigInteger.ZERO)
fact = BigInteger.ONE;
else
fact = x.multiply(factorial(x.subtract(BigInteger.ONE));
return fact;
}
def factorial(x: BigInt): BigInt = if (x == 0) 1 else x * factorial(x - 1)
© NovaTec
12.06.2013
14
Scala – Java Unterschiede
Viele kleine Vereinfachungen, z.B.
 ; am Zeilenende optional
 Leere Argumentklammern optional
 Keine Unterscheidung Statement und Ausdruck
 Implizite Getter und Setter
 Vereinfachte Konstruktoren
 Viele Typangaben optional
Viele leistungsfähige Verbesserungen -> Grundlage der Scala Pattern
 object
 Funktionsobjekte
 Traits
 Implicit Konvertierungen
 Selftype
© NovaTec
12.06.2013
15
Scala Packages und Klassen
package Beispielklasse {
class BoundedPoint(var x:Int, var y:Int) {
val maxVal:Int = 32000
if (x.abs > maxVal || y.abs > maxVal)
throw new IllegalArgumentException("Point too large")
}
def this(d:Int) = this(d, d)
def mirrored : BoundedPoint = {
return new BoundedPoint(y, x)
}
}
© NovaTec
12.06.2013
16
Scala Feature
object Definition
© NovaTec
12.06.2013
17
Scala Feature - Object Definition
Ein object ist die Definition einer Singleton Instanz einer Klasse
object MyObject {
val constant:Int = 2
var variable:String = "Hello World"
def method(param:Int) = variable * param
}
entspricht etwa
class MyObject$ ….
val MyObject = new MyObject$()
© NovaTec
12.06.2013
18
Object Verwendung
Object als Träger von „static“ Variablen und Methoden
 Scala Terminologie: Ein „Companion Object“ einer Klasse
class BoundedPoint….
object BoundedPoint {
val unit = new BoundedPoint(0)
….
}
Object als Modul
 Ein Package ist ein Object (mit impliziter Definition)
Object als Singleton
© NovaTec
12.06.2013
19
Singleton Pattern
Ein unsichtbares Pattern – object ist ein Singleton
Kein Bedarf an getInstance()
object Singleton
{
}
var sharedValue = 42
 Singleton sharedValue
© NovaTec
12.06.2013
20
Factory Pattern - Typsichere Parametrische Factory
Nutzt: Pattern Matching, Sealed Klassenhierarchie
Leistet: Compilezeit-Prüfung der Factory Parameter
sealed abstract class FactoryItem
case object Type1 extends FactoryItem
case object Type2 extends FactoryItem
object Factory {
def createItem ( which:FactoryItem) = which match {
case Type1 => new Item1()
case Type2 => new Item2()
}
}
Factory.createItem(Type2)
© NovaTec
12.06.2013
21
Scala Feature
Funktionen
© NovaTec
12.06.2013
22
Scala Feature - Funktionen
Funktionen sind Objekte
 Können in Variablen gespeichert werden
 Als Parameter übergeben werden
 Zur Laufzeit erzeugt werden
Literalsyntax: (arg1,… argN) => Ausdruck
val nameHasUpperCase = name.exists(char => char.isUpperCase)
boolean nameHasUpperCase = false;
for (Character char : name) {
if (Character.isUpperCase(char)) {
nameHasUpperCase = true;
break;
}
}
© NovaTec
12.06.2013
23
Scala Feature - First-class Funktionen
Funktionen sind Objekte
Implementierung: Objekte mit einer Methode apply(parm1, … parmN)
Methoden können als Funktionsobjekte extrahiert werden
Idiomatische Nutzung:
 Siehe andere funktionale Programmiersprachen (und den Scala Blog)
 Ersetzung von (anonymen) Hilfsklassen als Träger von Methoden in Java Pattern
 Definition von neuen Kontrollstrukturen
© NovaTec
12.06.2013
24
Cell Pattern
Idiomatisch: Objekte erhalten Funktionscharakter wenn es eine apply Methode gibt
Problem: Wir müssen eine Variable per Referenz übergeben
Lösung: Wir definieren ein Value-Objekt mit Funktionsverhalten
class Cell[T](var value:T) {
def apply() = value
def update(v:T) = value=v
}
val cell = new Cell ("")
cell() = "Hello World"
println(cell())
© NovaTec
12.06.2013
25
Iterator Pattern
Iteratoren werden „internalisiert“ und mit dem Iteratorbody parametrisiert
Java:
List<String> result = new ArrayList<String>;
for (String elem: list) {
if (elem.indexOf("World") >= 0)
result.add(elem)
}
Scala:
list.filter(x:String =>x.contains("World"))
Vorteile:
 Multiple Iteratoren gekapselt in Collections
 Collection-Typ des Resultats wird durch die Collection bestimmt und nicht durch den Aufrufer
© NovaTec
12.06.2013
26
Visitor Pattern
Visitor = Iteration über Objektstruktur + Methode für jeden iterierten Elementtyp
Scala Lösung #1: Definiere internen Iterator wie bei einer Collection
 Bsp.: aTree.inorderDo(node:TreeNode => visit Funktionalität)
Scala Lösung #2: Rekursion über Objektstruktur mit Pattern-Matching
abstract class Expr
case class Num(n: Int) extends Expr
case class Sum(l: Expr, r: Expr) extends Expr
case class Prod(l: Expr, r: Expr) extends Expr
def evalExpr(e: Expr): Int = e match {
case Num(n) => n
case Sum(l, r) => evalExpr(l) + evalExpr(r)
case Prod(l, r) => evalExpr(l) * evalExpr(r)
}
© NovaTec
12.06.2013
27
Observer Pattern
Ziel:
 Benachrichtigung von Observern, wenn das Subject sich ändert
 Dynamische Registrierung von Observern
Scala Idiomatisch: Ersetzen einer Observer Klasse durch eine Funktion
case class Event
class Subject {
private var observers:List[(Event, Subject) => Unit] = Nil
def observe(observer: (Event, Subject) => Unit)=
observers = observer :: observers
def notify(evt:Event) = observers.foreach(_(evt, this))
}
subject.observe(e:Event, s:Subject => …..)
© NovaTec
12.06.2013
28
Lazy Funktionen
Ziel: Konditionaler Aufruf einer teuren Funktion
Scala kennt lazy Funktionsparameter
 Werden ohne Auswertung übergeben
 Können selber keine Parameter haben
if (Trace) System.out.println(expensive())
def trace(f: => Any)
{
if (Trace) println(f)
}
trace(expensive())
© NovaTec
12.06.2013
29
Funktionale Pattern – Lazy Lists
Lazy Parameter nur ein Beispiel für viele Pattern aus der funktionalen Welt
Schwerpunkt 1: Besondere Kontrollstrukturen
Stichwort: Continuations
Schwerpunkt 2: Infinite Datenstrukturen
Scala Streams implementieren potentiell unendliche Listen
© NovaTec
12.06.2013
30
Scala Feature
Trait
© NovaTec
12.06.2013
31
Scala Feature - Traits
Traits sind eine Mischung aus abstrakter Klasse und Interface
 „Interface auf Drogen“
 Können Typen, Variablen und abstrakte sowie konkrete Methoden enthalten
Traits mischen Verhalten zu Klassen (Mixin)
trait NoLogger { def log(level:Int, msg:String) = { } }
trait Logger extends NoLogger {
val loggerName = this.getClass.getName
override def log(level:Int, msg:String) =
println("["+level+":"+loggerName+"]" + msg)
}
class C extends SomeClass with Logger ….
© NovaTec
12.06.2013
32
Scala Feature - Traits
class MyClass extends SomeClass with Trait1 with Trait2 with Trait3 {….
Traits überschreiben vorhandene Definitionen in der Reihenfolge Rechts nach Links
 Hat nicht die Problematik mehrfacher Vererbung
 Trait3 überschreibt Trait2 überschreibt Trait1 überschreibt SomeClass
Idiomatisch:
 Traits dienen der statischen Parametrisierung von konkreten Objekten
Siehe das Decorator Pattern
 Traits dienen der Modularisierung
Siehe das Cake Pattern
© NovaTec
12.06.2013
33
Decorator Pattern (Stackable Trait)
Idiomatisch: Verwendung von Trait Mixins anstelle von Delegation
new A with T1
new A with T1 with T2
ergibt "T1 A"
ergibt "T2 T1 A"
Vorteil: Compilezeit-Operation, gut lesbar, Decorator enthalten nur geänderte Methoden
Nachteil: Decorator-Chain nicht dynamisch änderbar
class A {
}
trait T1 {
}
trait T2 {
}
© NovaTec
override def toString = "A"
override def toString = "T1" + super.toString()
override def toString = "T2" + super.toString()
12.06.2013
34
Implicit Konvertierung
© NovaTec
12.06.2013
35
Scala Feature - Implicit Definitionen
Schwieriges Thema und Kandidat für „Gefährlichstes Feature“ in Scala
Sehr wichtiges Feature für besonders fortgeschrittene Scala-Pattern
Dringende Empfehlung: Nutzung auf festgeschriebene Pattern beschränken!
Implizite Definitionen werden automatisch (sofern eindeutig) vom Compiler gesucht und
verwendet
© NovaTec
12.06.2013
36
Scala Feature - Implicit Definitionen
Methoden und Methodenparameter können als implizit gekennzeichnet werden
 Der Compiler löst Typkonflikte auf, indem er nach passenden impliziten Definitionen sucht
 Für die folgenden Pattern genügt etwas Intuition  Mehr Präzision im Scala Blog
Implicit Methoden werden als versteckte Wrapper verwendet
Implicit Parameter werden automatisch mit einem implicit Val aufgefüllt
Idiomatische Nutzung:
 Automatische Typkonvertierung (siehe Adapter Pattern)
 Erweiterung geschlossener Klassen (siehe Pimp My Library Pattern)
 Statisch aufgelöste Dependency Injection (siehe Type Classes Pattern)
© NovaTec
12.06.2013
37
Adapter Pattern
Automatische Konvertierung in eine anonyme Adapter-Unterklasse
Keine Veränderung an den Originalklassen
class Adapter {
def someMethod() = ...
}
class Adaptee {
def differentMethod() = ...
}
val adapter: Adapter = new Adaptee Compiler sucht hier nach impliziter Methode Adaptee=>Adapter
implicit def targetAdapteeConv(x:Adaptee):Adapter = new Adapter {
override def someMethod() = x. differentMethod()}
 val adapter: Adapter = targetAdapteeConv(new Adaptee)
© NovaTec
12.06.2013
38
Pimp My Library Pattern
Problem: Wie erweitere ich eine bestehende API ohne explizite Konvertierungen in
Extension-Unterklassen, ohne Wrapper und ohne Casts?
Lösung: Eine Variante des Adapter-Pattern auf Methodenebene.
 Eine anonyme Klasse mit der gewünschten Methode X über dem vorhandenen Typ T
 Eine implizite Konvertierung von T zur anonymen Klasse für den Aufruf von X
Kriterien:
 Verwende anonyme Klassen weil es idiomatischer ist und nicht den Namensraum zu müllt
Beispiel: „3 :: 52“ als Ausdruck für eine Calendar Instanz mit Uhrzeit
Dazu müssen wir einen :: Operator der Klasse Integer „unterschieben“
Library Beispiel: ArrayOps  Array mit erweiterten Collection-Funktionen
© NovaTec
12.06.2013
39
Pimp My Integer
3::52  Compiler sucht nach einer impliziten Konvertierung von Int zu einem Typ mit ::
Ergebnis: pimp(52).::(52)
implicit def pimp(minutes: Int) = new {
def ::(hours:Int) = {
var cal = java.util.Calendar.getInstance()
cal.set(java.util.Calendar.HOUR_OF_DAY, hours)
cal.set(java.util.Calendar.MINUTE, minutes)
cal
}
}
Vorteile:
 Einfache, lokale Erweiterung
 Leichtgewichtig: wir erzeugen kleine Instanzen mit einer Methode
 Erweiterung wird durch den Scope kontrolliert
© NovaTec
12.06.2013
40
Self Type
© NovaTec
12.06.2013
41
Scala Feature - Selftype
Selftype ist eine Art Cast von this auf einen gewünschten Zieltyp der konkreten Objekte
class MyClass {
self: SomeType => ….
}
MyClass ist dadurch abstrakt (wenn MyClass != SomeType)
Konkrete Unterklasse muss alle Definitionen von SomeType enthalten!
Idiomatische Nutzung:
 Constraint auf die Komposition von Klassen aus Traits
© NovaTec
12.06.2013
42
Scala Feature - Selftype (Anhand eines Beispiels)
trait Hello { def hello = "Hello" }
class Test { self: Test with Hello =>
val helloWorld = hello + "World"
}
// das ist der Selftype
// hello kommt aus Trait Hello
new Test
error: class Test cannot be instantiated because it does not conform to its self-type Test with Hello
val ok = new Test with Hello
ok.helloWorld
 HelloWorld
Schlechtere Alternative:
class Test extends Hello { val helloWorld = hello + "World"}
Warum schlechter?
© NovaTec
12.06.2013
43
Cake Pattern
Problem:
 Dekomposition von Code in Module bei kreuzweise Abhängigkeiten der Module
 Deklarative Komposition des Ergebnis ohne Rückgriff auf Delegation, DI o.ä. Techniken
 Austauschbare Implementierungen der Module
var varModulA:Int
def methModulA() = methModulB(valModulB)
val valModulB:Int
def methModulB(i:Int) = i*varModulA
Zwei Codefragmente mit kreuzweiser Abhängigkeit
Wie kann man diese unabhängig entwickeln und am Ende zusammenfügen?
© NovaTec
12.06.2013
44
Modulare Komposition 1. Versuch
trait ModuleA {
var varModulA:Int
def methModulA() = methModulB(valModulB)
}
trait ModuleB {
}
val valModulB:Int
def methModulB(i:Int) = i*varModulA
Dies ist nicht compilierbar!
Java: Explizite Referenz auf benutzte Module, DI und Delegation
Scala: Composite selftypes und Mixins
© NovaTec
12.06.2013
45
Cake Pattern
Cake bildet das modulare Design des Scala Compilers (Komposition verschiedener Module
zur Konstruktion des Compiler, der REPL und scaladoc)
Konzept:
 Dekomposition in Traits
 Scope-Abhängigkeit der Module ermöglicht durch zusammengesetzte selftypes
 Komposition in einer Klasse
 Statisch typbar wenn in der Klasse alle Abhängigkeiten aufgelöst sind
 Als ob alle Traits manuell in ein großes Modul zusammen kopiert wurden
Vorteile:
 Komposition auch bei zyklischen Abhängigkeiten kein Problem
 Keinerlei Overhead oder erhöhte Komplexität durch die Modularisierung
 Einfacher Zusammenbau von Implementierungsvarianten
© NovaTec
12.06.2013
46
Cake Pattern Skizze
trait ModuleA {
self:ModuleA with ModuleB =>
var varModulA:Int
def methModulA() = methModulB(valModulB)
}
trait ModuleB {
self:ModuleA with ModuleB =>
val valModulB:Int
def methModulB(i:Int) = i*varModulA
}
class Composite extends ModuleA with ModuleB {
….
}
© NovaTec
12.06.2013
47
Type Class Pattern
Wichtiges Pattern im Scala 2.8 Collection-Design
Problemstellung: Wir müssen verschiedene Klassen mit polymorph nutzbaren Methoden (einer
neuen Feature) ausstatten ohne die Klassen zu erweitern.
Lösung: Generalisierte Form des Pimp My Library Pattern.
Idee:
Implementierungen einer Feature für die verschiedenen Klassen
Mache diese als implizite neue Klassendefinition verfügbar
Methoden die das Feature polymorph nutzen wollen, empfangen dieses durch einen impliziten
Methodenparameter
Vorteile:
Vermeidet Vererbung und Modifikation von Klassen
Eine Methode für verschiedene Parametertypen
Einfache Benutzung durch implizites DI der benötigten Konzeptimplementierung
Reichweitensteuerung über Scoping einfach
© NovaTec
12.06.2013
48
Type Class Pattern Beispiel
trait InvertableFeature[CType] { def inverse (obj:CType) : CType }
implicit val intInvertable = new InvertableFeature[Int] {
def inverse (i:Int) = -i
}
implicit val seqInvertable = new InvertableFeature[Seq] {
def inverse (s:Seq) = s.reverse
}
def inverted[CType](obj:CType)(implicit feature:InvertableFeature[CType])
feature.inversed(obj)
=
inverted(42)  inverted[Int](42)(inInvertable)  -42
inverted(1::2::3::Nil)  inverted[Seq](1::2::3::Nil)(seqInvertable)  List(3,2,1)
inverted("HelloWorld")  Compiler Fehler
© NovaTec
12.06.2013
49
Scala Typen
© NovaTec
12.06.2013
50
Scala Feature - Typen
Typen können unabhängig von Klassen- oder Interface Definition definiert werden
Typen können Member von Klassen, Objecten und Traits sein
Typen können als Typparameter (wie in Generics) verwendet werden
Typen können zusammengesetzt und verfeinert werden
Idiomatische Nutzung von Typen in Pattern
 Compilezeit Kontrolle  Typesafe Builder, Phantom Types
 Polymorphie  Duck Typing
© NovaTec
12.06.2013
51
Type Member Beispiel
Typen können als Member einer Klasse, Object oder Trait definiert werden
class AbstractClass {
type T
type U <: Seq[T]
….
}
class RealClass extends AbstractClass {
type T = Int
….
}
Vergleichbar mit Typ-Parameter
Warum beide Optionen?
Reduktion der Zahl der Typparameter
Kapselung der Typ-Parametrisierung
© NovaTec
12.06.2013
52
Struktur Typen
Notation:
{
abstrakte Definitionen
}
Vergleichbar mit einem Ad-Hoc definierten Interface
Kern von "Duck Typing"
Beschreibt einen Typ eines Objektes anhand des notwendigen Verhaltens
type Sizable = { def size: Int }
var s:Sizable = "Hello World"
s = List(1, 2, 3)
© NovaTec
12.06.2013
53
Type Refinement
"Verfeinert" einen bestehenden Typ durch weitere Definitionen
Typname { DEFINITIONEN }
Klassendefinition ist Refinement der Oberklassen und Traits 
class A extends B { DEFINTIONEN }
new A
entspricht new B { DEFINITIONEN }
Kann explizit als Typ verwendet werden
 Zur Veränderung eines Variablentyps
 Zur Veränderung einer neuen Instanz
new Dog { def speak() = bark }
© NovaTec
12.06.2013
54
Phantom Type Pattern
Ziel: Überprüfung des Programmablaufs zur Compilezeit
Beispiel: Sicherstellen dass im Builder Pattern eine konsistente Menge von Builder
Methoden aufgerufen wurde
Lösung:
 Phantom Types als Zustände eines endlichen Automaten zur Compilezeit
 Typparameter oder Typ Member halten den aktuellen "Zustand des Automaten"
 Methodenaufrufe verändern den Zustand über ihren Return-Typ
Phantom Type stammt aus Haskel
Vereinfacht hier: Ein Typ der nicht in Variablen verwendet wird
© NovaTec
12.06.2013
55
Phantom Type Beispiel Skizze
case class SocketState[+S <: State]()
trait State
trait Closed extends State
trait Opened extends State
Closed und Opened sind Phantom Types
trait SocketProcessor {
val openSocket: SocketState[Closed] => SocketState[Opened]
val readSocket: SocketState[Opened] => SocketState[Opened]
val closeSocket: SocketState[Opened] => SocketState[Closed]
}
val result:SocketState[Closed] = (openSocket readSocket closeSocket)(new
SocketState[Closed])
val result:SocketState[Closed] = (openSocket closeSocket readSocket )(new
SocketState[Closed])
© NovaTec
12.06.2013
56
Typesafe Builder Pattern (Phantom Type)
Typsichere Pizza Bäckerei
 Phantom Type beschreibt Zustand der Pizza
 Implizit Konvertierung zur Prüfung des korrekten Endzustands
© NovaTec
12.06.2013
57
Duck Typing
Duck Typing wurde in Anlehnung an ein Gedicht von James Whitcomb Rileys benannt. In
der Kurzform: If it walks like a duck and quacks like a duck, it is a duck.
Ziel: Polymorphe Nutzung von Objekten aus unabhängigen Klassenhierarchien
Verschiedenste Objekte sollen austauschbar sein
 Unabhängig von ihrer Klassenhierarchie
 Sie müssen nur die benötigten Methoden implementieren
Polymorphie von Smalltalk und Ruby
Strategie:
 Structural Type zur Definition der erforderten Methoden
 Pimp my Library zur Anpassung existierenden geschlossener Klassen
Live Beispiel
© NovaTec
12.06.2013
58
Noch nicht müde?
scala.novatec-gmbh.de
Vielen Dank!
© NovaTec
12.06.2013
59
Scala Klassenhierarchie
© NovaTec
12.06.2013
60
Exkurs: Typausdrücke für Instanzen
new A with T1 with T2
Com pound Typ
new A { def toString = "Anonymes A" }
Refinem ent
var duck:{ def toString:String } = new A
Struk turtyp (Duck Typing)
Idiomatisch:
 Sehr häufige Verwendung von Typausdrücken anstelle von Klassendefinitionen
•
Führen intern zu Java anonymen Klassen
 Reduktion der Zahl der konkreten Klassendefinitionen im Vergleich zu Java
 Expliziter Ausdruck der Kompositions-Struktur einer Instanz
© NovaTec
12.06.2013
61