5

I would want to have a builder for creating a complex object, for example Employee.

I would want to be able to create my objects in two ways:

Case 1. Get Employee with default values

Case 2. Get Employee with default values, but then be able to change certain fields only

So, I am thinking of mixing Factory and Builder.

Something like that:

Case 1:

//Get a fully configured Employee with default values

Employee employee = EmployeeFactory.getDefault()

Case 2:

//Get a fully configured builder with default values, but change only the salary
//before finally building the Employee

Employee employee = EmployeeFactory.getDefaultBuilder().setSalary(5000).build();

Basically my Factory will either return an already built Employee or an EmployeeBuilder so I can further change only couple of fields per need.

Per my understanding of the Factory pattern by the book, it seems that Factory concept is broken as it returns both an object and a builder.

Is there anything wrong with this approach in your opinion?

8
  • 1
    Returning a builder and a concrete object is going to shock others, that would be enough for me to not go that way.
    – Ccm
    Commented Apr 5 at 7:12
  • 2
    If you just need a static class name that people can type as a starter prompt for building different kinds of Employee, Factory is probably not the right name as it will get confused with the actual Factory design pattern. Commented Apr 5 at 8:10
  • 5
    A builder is already a kind of a factory (a factory doesn't have to be a static class). So, I wouldn't go through a static function, unless your team absolutely insists on that for consistency with other code. You could just use new EmployeeBuilder().build() to create an instance with the default values (this makes sense, but may not be obvious to everyone, so make sure to point this out in the docs and/or documentation comments associated with the builder class). Commented Apr 5 at 14:14
  • 3
    Since there are two distinct and well-known Builder patterns (GoF and Bloch) it would be good to explicitly clarify that you are talking about the Bloch Builder here. Also, 'Factory' can be understood in a number of ways. I think you are talking about a Factory method which is (in GoF) more than just a method that returns instances (which is completely fine, IMO)
    – JimmyJames
    Commented Apr 5 at 17:58
  • 1
    You have mentioned no reason at all, why you need a factory, or a builder. Is there such a reason? Otherwise I'd say both is "overengineered waste" and should be avoided. If it is a hobby or school project to play around with the patterns, go ahead and create whatever pattern monster you have fun creating though.
    – nvoigt
    Commented Apr 6 at 11:08

6 Answers 6

3

This design decision hinges on whether you need separate derived types of employees. If Employee is an interface or abstract type, there are behavioral differences between the types of employees, and there are also situations where you can treat all employees the same, then a factory may be justified. The factory should return a concrete implementation cast up to the abstract Employee.

And then immediately we bang our heads against the reason why we need a builder. I would expect an Employee factory to return Employee objects — fully initialized and ready to use. An EmployeeBuilder does not represent a fully initialized and usable Employee.

Instead, consider that you have created an abstract Employee builder instead. This is more akin to the abstract factory pattern.

I can't say from your question whether this is a "good idea". It all depends on context, and the problems your application needs to solve. You will need to judge for yourself whether the object construction needs of your application justify this increase in complexity. For that, you will need to study and understand both the Joshua Bloch Builder Pattern and the Abstract Factory Pattern to see if it is an appropriate application of those design patterns, and that a simpler more straight forward approach doesn't work just as well, or is more of a burden on the programmer.

Things change of you only have an Employee class with no derived types. In this case, get rid of the factory. As others have pointed out, any defaults for a new Employee can be included in the builder.

Some additional closing thoughts to provide guidance:

  • If the programmer has decided ahead of time which kind of employee is needed, then you lose the benefits of a factory. You can still use a builder, if it makes sense, but you would initialize a concrete builder, say ManagementEmployeeBuilder. No use in obfuscating the obvious. If your code needs to work with a particular kind of employee, just work directly with it. Don't make me jump through some pointless abstraction when I already know what I'm dealing with.

  • If EmployeeFactory.getDefault() just returns new Employee() then get rid of the factory. Remember that constructors are also static methods, we just call them with the new keyword. Again, don't make me jump through a pointless abstraction when a suitable pre-existing code construct does the trick just as well.

  • Don't go around creating factories in real application code just because you think things might get complicated in the future. The YAGNI Principle is a counterbalance here.

  • Do go around creating lots of factories for learning purposes. You get to play with the pattern.

    • This should be followed by reimplementing the same behavior without factories so you can compare the benefits and drawbacks.

Other questions in this community have covered topics related to this, which you might find interesting:


The more I read this question, the more I want to see reasons why the factory pattern is justified. It's not that you can't use a factory and builder, but what benefits are realized by using them together that other code constructs don't provide on their own? That's the burning question for you to answer, and strangers on the Internet can't answer that for you without seeing the full code you are dealing with.

1
  • 2
    "If EmployeeFactory.getDefault() just returns new Employee() then get rid of the factory." Thank you, Greg! This made me realize that for some reason I am leaning to creating objects through factories/builders even when they can be created with a simple new.
    – CuriousGuy
    Commented Apr 7 at 16:55
9

As always, you can do what is best suited to your domain and concrete problem.

In any case, this looks like mixing a concrete factory with the Bloch builder pattern. In this case, I do not see the benefit of the factory, as you can just have it all wrapped up (including default values) in the builder and just use new EmpBuilder() // with Default Values. You could give the Builder some "static factory methods", e.g. EmpBuilder.default() // returns new EmpBuilder.

Note that this may be different if you use the abstract factory pattern, or the GOF builder pattern.

One more alternative: Use the factory with a configuration (config can be constructed using the Bloch builder):

  EmpFactory.get(new Config().withSalary(5000));

This could also work with the abstract factory then.

Or just use the factory by passing in the parameters:

  EmpFactory.get(/* salary: */ 5000);
5
  • 1
    I'm racking my brain trying to understand when I'd ever need a Factory pattern together with a Builder pattern, and I often times one or other is enough. A Factory can always turn into an AbstractFactory for more complexity, or a Build pattern could use inheritance to hide some complexities which would otherwise be hidden to the caller. I do like your suggestion about the configuration class. I've seen libraries such as Hibernate use the concept of a Context which is a similar concept.
    – Neil
    Commented Apr 5 at 13:42
  • +1, but one nitpick: the distinction you draw between a concrete factory and an abstract factory is better drawn between a factory class with static methods and a factory class with instance methods. One reason for the latter is that it lets the factory class be abstract, but that's not the only reason; other reasons include the ability to inject dependencies into the factory, the ability to inject the factory into its clients, expensive/heavyweight factory initialization logic (e.g. that reads configuration from a DB or filesystem), and so on.
    – ruakh
    Commented Apr 5 at 22:04
  • @ruakh, thanks for the Feedback. Imo its more important to distinguish concepts/patterns and not the Implementation of those. My code snippets are only meant to support individual points, not show an actual Implementation. Maybe I'll find the time to update and include your suggestions later.
    – sfiss
    Commented Apr 6 at 5:32
  • @sfiss: Re: "Imo its more important to distinguish concepts/patterns and not the Implementation of those": Sorry, I don't understand. Are you saying that for you, the concepts/pattern of "concrete factory" vs. "abstract factory" do not relate to whether, in the actual Implementation, the factory's type is concrete vs. abstract? If so, then you might want to either define what you mean by these terms, or link to some source that defines them in the senses that you mean.
    – ruakh
    Commented Apr 6 at 8:04
  • to me this answer seems wrong. OP says "I would want to have a builder for creating a complex object" and the answer is "use a factory, but pass in a config builder"? and the factory only ever returns Employee, we have no sub types of Employee, so is it a factory or a constructor? if its a constructor that takes a builder, doesnt that invalidate the builder pattern?
    – Ewan
    Commented Apr 7 at 9:04
6

A Factory normally returns different implementations of a class/interface, while a builder gives a fluent interface for configuring a single type.

So if you factory returns a builder you might expect it to return different builder types? which doesn't sound like what you want.

I think it would be fine to have a builder with a GetDefault() method and not worry about a factory at all

var builder = new EmployeeBuilder();
var employee1 = builder.Default().Build();
var employee2 = builder.Default().WithSalary(200).WithName("bob").Build();
4
  • I would argue the fluent interface is less important than providing the distinction between a "partially initialized" Employee and a "ready-to-go" Employee.
    – chepner
    Commented Apr 6 at 11:56
  • @chepner good point, amended answer to include
    – Ewan
    Commented Apr 6 at 12:45
  • That's ok (+1), but still more complicated than necessary. There should be no necessity for this kind of Default() method - new EmployeeBuilder() should already create an object with the default values.
    – Doc Brown
    Commented Apr 7 at 8:18
  • yeahhhh, I did think about that, but here I think you would expect builder.Build() to product a blank employee, a "code default" if you will, salary 0, where as a default employee the OP writes about is more like a specific instance of an employee. I was thinking of : TelemetryConfiguration.CreateDefault and similar
    – Ewan
    Commented Apr 7 at 8:51
4

With a Bloch Builder you get the default values like this:

//Get a fully configured Employee with default values
Employee employee = employeeBuilder.build();

If that blows up, it doesn't offer default values.

//Get a fully configured builder with default values, but change only the salary
//before finally building the Employee

Employee employee = employeeBuilder.setSalary(5000).build();

Where this gets interesting is when you have more than one set of "default" values. In that case the sets of values need names.

EmployeeBuilder internBuilder = employeeBuilder.setSalary(5000);

This gives you a builder that defaults to intern employee values. You can send this off to other code that will set other settings before finally building it.

EmployeeBuilder grantExecutiveAccess(EmployeeBuilder employeeBuilder){
    return employeeBuilder
        .setExecutiveBathroomKey(true)
        .setParkingPermit("A")
    ;
}

Here the name of these "defaults" is executive access. This way if another set of "defaults" becomes relevant you just need to give them a name.

Now was that a factory? Doesn't look like a typical one. It takes the same type as it returns. It returns what it was passed after mutating it. Call it a shunt if you like.

If there was such a thing as an executive intern employee you could build them like this:

EmployeeBuilder internBuilder = employeeBuilder.setSalary(5000);
Employee executiveIntern = EmployeeFactory
    .grantExecutiveAccess(internBuilder)
    .build()
;

The key lesson here is that builders are first class objects themselves. So you are perfectly allowed to pass them around.

As to whether this is a good idea, you have to admit this leaves you with a fair bit to digest. The charm of builders is that they are straight forward to use. If you're going to require mixing factories and builders when a flat builder with some extra keyboard typing solves the same problem you'd better have a problem complex enough to make that a poor choice. Having the ability to decouple intern construction code from executive construction code is nice. But do you really need it this badly?

The advantage of this method over adding some executive method to the builder is that adding the factory will leave the builder code untouched. Sometimes that's important. Just remember, you could also create a whole new builder. Just need a good name.

It should also be noted that when you take a Bloch Builder beyond just simulating named arguments you're heading into DSL territory. DSLs are very powerful but take a fair bit of work to set up. They should be reserved for cases where they will be used a lot to make up for that extra effort.

5
  • And if "intern" is a thing, you could have a BuildIntern() method, or AsIntern() that preconfigures or builds the intern with default values where appropriate. Commented Apr 5 at 17:43
  • @GregBurghardt yes, with EmployeeFactory.AsIntern(EmployeeFactory .grantExecutiveAccess(new EmployeeBuilder())).build() you have your executive intern without directly touching the builder. The irony here is Bloch Builders were invented to make construction of immutable objects easier for humans and we've removed the builder from the humans. Commented Apr 5 at 18:02
  • Well, I was thinking BuildIntern or AsIntern would go on the builder, thus removing the need for a factory. Commented Apr 5 at 18:44
  • @GregBurghardt also a possibility. Works better with code completion in your IDE. But now your builders interface is unstable as you think of new "default" sets. The more you go beyond just simulating named arguments the less this is simply a Bloch Builder. Commented Apr 5 at 18:59
  • @GregBurghardt Could make the default sets first class classes so you can add them as you please. intern.defaults(executive.defaults(new EmployeeBuilder())).build() Commented Apr 5 at 19:59
1

The reason you don't see this sort of thing happening is because the builders are used when we want the caller to specify details of the implementation being created, and factories are used when we do not want the caller to specify details of the implementation.

If you really have some kind of situation where you don't want the caller to know the implementation class, but you still want to provide the callers with a standard interface for setting up a whole bunch of implementation details, then what you're doing is OK, but unusual.

It looks to me, though, like there's a good chance that your use of either the factory or the builder pattern is misguided. Why are you using a factory? Why are you using a builder?

-1

Factory method design pattern definition according to wikipedia it is:

In object oriented programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.

Builder design pattern definition according to wikipedia it is:

The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the builder design pattern is to separate the construction of a complex object from its representation.

Concluding when instances of interfaces or base classes implemented or extended by classes that require a complex instantiation or initialisation then yes returning a builder from a factory it is a suitable approach, worthless to say...

EmployeeFactory.constructive().salary(...).employ();

...is readable while...

Emplyee employee = new Employee();
employee.setSalary(...);
...

...although is readable has a jerky narative.

Otherwise, sure, it is not a proper construction to return a builder from a factory just to implement some design patterns.

1
  • 1
    Wikipedia, where you cited from, refers to the Builder pattern from the GoF book. The question, however, refers to Bloch's builder pattern, which is a workaround for Java's "telescoping constructor" problem (a problem which does not exist in languages with named parameters).
    – Doc Brown
    Commented Apr 7 at 8:26

Not the answer you're looking for? Browse other questions tagged or ask your own question.