Anybody written a builder pattern like this? For cases where you have quite large records with lots of fields that are optional, and frequently left at their default values.
Its nice to use in the sense that you only need to set things when they are actually needed. Also if you have several records like this in a more complex data model and the same field names exist in multiple record types, by scoping the setter functions inside the builder you avoid the name clashes you would get if they were top-level functions.
example : LongOptionalRecord
example =
builder "id-123" "Widget"
.addParam "p1"
.addParam "p2"
.withAttr "env" "prod"
.withOption "special"
.addAndSoOn 42
.addAndSoOn 7
.build
type alias LongOptionalRecord =
{ name : String -- required
, id : String -- required
, params : List String
, attrs : Dict String String
, option : Maybe String
, andSoOn : Set Int
}
type Builder =
Builder
{ withParams : List String -> Builder
, addParam : String -> Builder
, withAttrs : Dict String String -> Builder
, withAttr : String -> String -> Builder
, withOption : String -> Builder
, withoutOption : Builder
, withAndSoOn : Set Int -> Builder
, addAndSoOn : Int -> Builder
, build : LongOptionalRecord
}
builder : String -> String -> Builder
builder id name =
builderFrom
{ name = name
, id = id
, params = []
, attrs = Dict.empty
, option = Nothing
, andSoOn = Set.empty
}
builderFrom : LongOptionalRecord -> Builder
builderFrom rec =
{ withParams =
\params ->
builderFrom { rec | params = params }
, addParam =
\param ->
builderFrom { rec | params = rec.params ++ [ param ] }
, withAttrs =
\attrs ->
builderFrom { rec | attrs = attrs }
, withAttr =
\key value ->
builderFrom { rec | attrs = Dict.insert key value rec.attrs }
, withOption =
\value ->
builderFrom { rec | option = Just value }
, withoutOption =
builderFrom { rec | option = Nothing }
, withAndSoOn =
\ints ->
builderFrom { rec | andSoOn = ints }
, addAndSoOn =
\n ->
builderFrom { rec | andSoOn = Set.insert n rec.andSoOn }
, build = rec
}
|> Builder