I'd put the fluent api to it's own "builder" class seperate from the object it is creating. That way, if the client doesn't want to use the fluent api you can still use it manually and it doesn't pollute the domain object (adhering to single responsibility principle). In this case the following would be created:
Car
which is the domain object
CarBuilder
which holds the fluent API
The usage would be like this:
var car = CarBuilder.BuildCar()
.OfBrand(Brand.Ford)
.OfModel(12345)
.PaintedIn(Color.Silver)
.Build();
The CarBuilder
class would look like this (I'm using C# naming convention here):
public class CarBuilder {
private Car _car;
/// Constructor
public CarBuilder() {
_car = new Car();
SetDefaults();
}
private void SetDefaults() {
this.OfBrand(Brand.Ford);
// you can continue the chaining for
// other default values
}
/// Starts an instance of the car builder to
/// build a new car with default values.
public static CarBuilder BuildCar() {
return new CarBuilder();
}
/// Sets the brand
public CarBuilder OfBrand(Brand brand) {
_car.SetBrand(brand);
return this;
}
// continue with OfModel(...), PaintedIn(...), and so on...
// that returns "this" to allow method chaining
/// Returns the built car
public Car Build() {
return _car;
}
}
Note that this class will not be thread safe (each thread will need it's own CarBuilder instance). Also note that, even though fluent api is a really cool concept, it probably is overkill for the purpose of creating simple domain objects.
This deal is more useful if you're creating an API for something much more abstract and has more complex set up and execution, which is why it works great in unit testing and DI frameworks. You can see some other examples under the Java section of the wikipedia Fluent Interface article with persistance, date handling and mock objects.
EDIT:
As noted from the comments; you could make the Builder class a static inner class (inside Car) and Car could be made immutable. This example of letting Car be immutable seems a bit silly; but in a more complex system, where you absolutely don't want to change the contents of the object that is built, you might want to do it.
Below is one example of how to do both the static inner class and how to handle an immutable object creation that it builts:
// the class that represents the immutable object
public class ImmutableWriter {
// immutable variables
private int _times; private string _write;
// the "complex" constructor
public ImmutableWriter(int times, string write) {
_times = times;
_write = write;
}
public void Perform() {
for (int i = 0; i < _times; i++) Console.Write(_write + " ");
}
// static inner builder of the immutable object
protected static class ImmutableWriterBuilder {
// the variables needed to construct the immutable object
private int _ii = 0; private string _is = String.Empty;
public void Times(int i) { _ii = i; }
public void Write(string s) { _is = s; }
// The stuff is all built here
public ImmutableWriter Build() {
return new ImmutableWriter(_ii, _is);
}
}
// factory method to get the builder
public static ImmutableWriterBuilder GetBuilder() {
return new ImmutableWriterBuilder();
}
}
The usage would be the following:
var writer = ImmutableWriter
.GetBuilder()
.Write("peanut butter jelly time")
.Times(2)
.Build();
writer.Perform();
// console writes: peanut butter jelly time peanut butter jelly time
Edit 2: Pete in the comments made a blog post about using builders with lambda functions in the context of writing unit tests with complex domain objects. It is an interesting alternative to make the builder a bit more expressive.
In the case of CarBuilder
you need to have this method instead:
public static Car Build(Action<CarBuilder> buildAction = null) {
var carBuilder = new CarBuilder();
if (buildAction != null) buildAction(carBuilder);
return carBuilder._car;
}
Which can be used as this:
Car c = CarBuilder
.Build(car =>
car.OfBrand(Brand.Ford)
.OfModel(12345)
.PaintedIn(Color.Silver);
Your concerns are very much valid and they tell me your original easy caching solution is eventually becoming part of your architecture which naturally brings a new level of issues as you described yourself.
A good architectural solution to caching is to use annotations combined with IoC which solves several problems you described. For example:
- Allow you to better control the life-cycle of your cached objects
- Allow you to replace the caching behavior easily by changing the annotations (instead of changing the implementation)
- Let you easily configure a multi-layered cache where you could be storing in memory then disk cache for example
- Let you define the key (hash) for each method in the annotation itself
In my projects (Java or C#) I use Spring caching annotations. You can find a brief description here.
IoC is a key concept in this solution because it allows you to configure your caching system anyway you want.
In order to implement a similar solution in Python you have to find how to use annotations and search for a IoC container that allows you to build proxies. That's how the annotations work in order to intercept all method calls and provide you this particular solution for caching.
Best Answer
Fluent Interface
I've always heard of this method being called a 'fluent interface', as coined by Eric Evans (of Domain Driven Design fame) and Martin Fowler (of Agile Manifesto fame).
The main drawbacks are the readability (which some folks love and some hate), and the fact that it can be harder to debug in some cases because the entire chain of actions may be considered a single statement when stepping through it.
I certainly don't consider it an anti-pattern, although I've only used the technique a few times myself.