Created
April 5, 2014 12:30
-
-
Save vkostyukov/9991383 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This is an immutable builder patter implemented in Scala within OO style. | |
* | |
* There is might be a better approach (i.e., pattern matching, case classes, etc) | |
* in implementing this idea within FP style, but the overall picture is robust: | |
* | |
* (a) there is no mutable state | |
* (b) it's a pure FSM (Finite State Machine) | |
* | |
* I'll try to keep this gist updated along with any new ideas regarding this | |
* implementation. Please, do not hesitate to suggest any ideas. | |
* | |
* Why do we need such things like an immutable builder? | |
* | |
* 1. It's fun | |
* 2. It deals with parameters with no default values | |
* 3. It avoids the cascade of if-elseif-else blocks for the complex building logic | |
* (i.e., depending on the specified parameters some object post-processing | |
* may be involved or different object types may be produced) | |
* | |
* How to use this builder? | |
* | |
* val o = TerminalBuilder // always start from a terminal state | |
* .foo(10) // state-transition: Terminal -> Foo | |
* .bar("Bar") // state-transition: Foo -> Bar | |
* .build // commits the building process and rollbacks the state-machine to | |
* // to its initial state (a terminal state) along with accumulating | |
* // parameters being used for final building | |
*/ | |
// A placeholder for a type being built | |
object Obj | |
// An interface being exposed to user via API | |
trait ImmutableBuilder { | |
def foo(i: Int): ImmutableBuilder | |
def bar(s: String): ImmutableBuilder | |
def build: Obj | |
} | |
// An internal builder API | |
trait UnderlyingBuilder extends ImmutableBuilder { self => | |
// state transition routines | |
def foo(i: Int): ImmutableBuilder = new FooedBuilder(i, self) | |
def bar(s: String): ImmutableBuilder = new BarredBuilder(s, self) | |
// an internal API for building | |
def build(i: Int): Obj | |
def build(s: String): Obj | |
def build(i: Int, s: String): Obj | |
} | |
// A non-terminal builder, which should be inherited | |
abstract class NonTerminalBuilder(underlying: UnderlyingBuilder) | |
with UnderlyingBuilder { | |
// just forward all the request | |
def build(i: Int) = underlying.build(i) | |
def build(s: String) = underlying.build(s) | |
def build(i: Int, s: String) = underlying.build(i, s) | |
} | |
// Foo state | |
class FooedBuilder(i: Int, underlying: UnderlyingBuilder) | |
extends NonTerminalBuilder(underlying) { | |
// there's something new we can tell the underlying builder - | |
// a new integer parameter | |
def build = underlying.build(i) | |
def build(s: String) = underlying.build(i, s) | |
} | |
// Bar state | |
class BarredBuilder(s: String, underlying: UnderlyingBuilder) | |
extends NonTerminalBuilder(underlying) { | |
// there's something new we can tell the underlying builder - | |
// a new string parameter | |
def build = underlying.build(s) | |
def build(i: Int) = underlying.build(i, s) | |
} | |
// A terminal state builder | |
object TerminalBuilder | |
with UnderlyingBuilder { | |
// an actual building process | |
// every methods represents a final state within a finite set of | |
// available parameters that should be used for building of a concrete instance | |
def build = Obj | |
def build(i: Int) = Obj | |
def build(s: String) = Obj | |
def build(i: Int, s: String) = Obj | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment