t = TemplateBuilder() .withFoo(foo) .withBar(bar) .excludeBaz() .build()
over:
t = Template(foo=foo, bar=bar, baz=none)
t = TemplateBuilder() .withFoo(foo) .withBar(bar) .excludeBaz() .build()
over:
t = Template(foo=foo, bar=bar, baz=none)
ipv4 = IPAddress().v4("127.0.0.1").build()
ipv6 = IPAddress().v6("::1").build()
Trying to perform something like this in Python with merely a constructor on an IPAddress type would lead to a not-so-obvious interface (such as use X set of named args to construct a v4 address or use Y set of named args to construct a v6 address, but using X & Y in the same constructor is a runtime error). This is my contrived example for where the builder pattern might make sense.With your example, I don't see any compelling advantage to use the builder pattern. In fact, I'd argue as-is, the builder is unnecessary, is more verbose, adds additional complexity, and you should just use the constructor with named args instead.
The point behind the builder pattern is to perform nontrivial initialization that is hard/difficult/impossible to perform in a normal constructor a la C++, C#, Java, etc. If you're not performing nontrivial initialization, you've just introduced extra verbosity and complexity for no gain, so don't use the pattern then. This is, of course, just my opinion.
For example, if you see code that has a lot of overloaded constructors followed by an `init` function that must be called after construction, or code with a lot of overloaded `init`-type functions, only one of which shall be called; the builder pattern might make sense there.
ipv4 = IPAddress.v4("127.0.0.1")
ipv6 = IPAddress.v6("::1")
KISS.That is just horrible...
> maybe parts of the construction might be conditional
No builder pattern needed for that, just use optional arguments and/or an option/nullable type.
I'll post an example in a bit of what I mean, but using a builder lets me use functions to break down the template into readable pieces.
And I'm not saying that it is impossible, I'm talking about readability.