Faceted Builder

A free video tutorial from Dmitri Nesteruk
Software/Hardware Engineering • Quant Finance • Algotrading
Rating: 4.5 out of 5Instructor rating
22 courses
280,022 students
Faceted Builder

Lecture description

We look at a more complicated builder facade that exposes several sub-builders (builder facets) for building up parts of an object in a fluent manner.

Learn more from the full course

Design Patterns in C# and .NET

Discover the modern implementation of design patterns with C# and .NET

20:21:43 of on-demand video • Updated March 2022

Recognize and apply design patterns
Refactor existing designs to use design patterns
Reason about applicability and usability of design patterns
English [Auto]
So in the example that we've done so far, we've been using just one builder to build up a particular object. And we looked at how to implement this builder and even make it fluent. But sometimes a single builder isn't enough. And what you want is you want several builders which are responsible for building up several different aspects of a particular object, and you also want some sort of facade. And facade is another design pattern that we're going to take a look at later on, but we are going to encounter it in this demonstration. So let me explain to you why this is needed now. I'm going to use a bit of a synthetic example, but this example is simple enough to understand. So let's suppose you have a person now a person has two different classes of information. There is information regarding a person's address, so I might make a couple of public fields once again. So I'll make public string street address, I'll add postcode and I'll let city. So this is the information which pertains to the address. And you might want to have a builder just for building up the address in a fluent way. And then of course we'll have some employment information as well. So we'll have public string company name and position and I'll add another field public int annual income, for example. So this is quite a bit of information on the person and we might want to well, first of all, we might want to output this information. So I'll add formatting members, I'll just dump everything here. So we have a nice big two string implementation so we can see how the person is actually initialized. Now what I want to have is some kind of builder which actually builds up a person, but really I want several builders taking care of the process, so I want a nice API for building up the address, for building up the employment information and for jumping from building one to building another. And for this we make a builder facet or in fact we're going to have two builder facets, a facet for address and a facet for employment. So let's take a look at how to implement this. Now we're going to start, which might seem like an ordinary approach with a person builder, but the person builder isn't really a builder in the full sense of the word. It's a facade. Have to have a diva here, but never mind. So the person builder is a facade for other builders, so it doesn't actually build up person by itself, but it keeps a reference to the person that's being built up. That's one thing. And the second thing is it allows you access to those sub builders, if you will. So here's what it looks like. We have a protected person. Person equals new person. Now, I have to stress that this is a reference. It's a reference object. This is very important because if you were building up a struct, you would have a lot of problems with this approach that can be mitigated. But I'm just putting it out there so that you're aware of it. So we have a reference to the object that's being built up. In this case, it's a person and it's initialized here. Now, in addition, what we do is we expose other builders, but what builders, we haven't got any yet, so let's make a person job builder. So I'll make a person job builder. So a person job builder is designed for building up job information on a person object. But in addition to just being stand alone, it also inherits from person builder. Now, this is really weird. Why are we inheriting from it? You'll see why in a moment. It all becomes clear in a while. But for now, let's just focus on this object. So we need as a constructor argument to take a reference to the person that we're actually building. So I'm going to take a reference here. Actually, let's go into the generate menu, make a constructor, but I'm going to take a person person, and I'm going to assign this this person equals person like, so now what's happening here is that you are passing into the builder, the object that you're building up and you're storing it in the field that you inherited from person builder. So far so good. And now I can build that nice, good looking fluent API. So if I want to say that the person works at a particular place, I say public person, job builder at. I put the company name here as an argument and then what I do is I say person dot, company name equals company name and return this because it's all going to be a big fluent interface. Then I have the same thing for the position. So as a so the person works at this company as a and then string position. So I'll put that in here string position. So once again, we simply assign the field and then we return this. So person dot position equals position and then return this. And finally we have that annual income. So public person job builder earning int amount and then we just say person dot annual income equals amount and return this once again. Now why do we do all this? What is the point? Well, the point is that we can now start using this API. We can now make a person builder. So I'm going to say var PB equals new person builder. And then of course I can try building up a person. So we'll try doing var person equals and then I'm going to say person builder and I'll go to the next line and I'm going to put a dot in here. Now, so far, strangely enough, we're not getting much. It doesn't look like person builder even has an API for us to work with. So let's make an API. Now we want to expose person job builder from person builder. And this is actually really easy because well, we can just return a new instance with the provided argument that we're building up. So here's what it looks like. Public person, Job Builder works. So it's a public property called Works, and we're going to return a new person job builder, which takes an argument of person. The original person, the person that's being built up. So I'm going to say person here. So essentially we now have a property called Works and we can start using it so we can say person builder, dot works, dot add. And you can provide the company name Fabrikam, for example. And then I can go to the next line and just indent it nicely as a and I can say he works as an engineer and then earning, let's say, 123,000 rubles, for example. Notice as soon as I put the semicolon Resharper Reformats the whole thing. So that kind of ruins the presentation. I'm going to undo it for now. Okay, So this is one facet of person because employment information is a facet and there is another facet which is the person's address. So for that we simply make another builder. Hopefully you understand the process. So what I'm going to do is I'm just going to paste in a person address builder. So here we go. Person address builder Very simple. It also takes the person reference and I have to stress once again that this, this thing with references is convenient. We're building up on that same reference. We have a single reference to person that's being passed through all these sub builders, and that's fine. But if you have a value type, you could be in trouble, shall we say. Obviously not our case. So now that we have a person address builder, what I can say is I can say public person address builder lives and then return a new person address builder passing in the person once again. Okay, so what does this give us? Because you can see that we once again have a fluent interface. We have a method called Add. So the person lives at the street address with post code, so and so in such and such and city. And we can add this information anywhere in the person builder. So for example, I can go in here and I can say Lives dot add and I can say 123 London Road, and then I can sort of manually indent here and say in London with postcode as W one to a C, for example. So the reason why we can jump from building up the address to building up the employment information is because both the address builder as well as the employment builder inherit notice they inherit from person builder. So both of them actually expose every other builder out there. And as a consequence of this, yes, you can you can write something like person lives. Lives. Lives forever. That's completely fine. But, you know, that's just a side effect of the fact that you're trying to make things convenient to use. So what we've done is we've used two sub builders to present a fluent interface for building up a person. But interestingly enough, if we now write line this right line person, we're obviously not getting a person at the end because person is actually a person job builder. That's the last call. So the question is, well, how can we actually get a person without introducing another piece of API? And that is perhaps the icing on the cake in this case. So if we go to person builder, what I often do, which isn't really that correct of a programming approach, but I do this, I do public static, implicit operator person taking a person builder. PB and I simply return PB dot person. Okay. Small P, obviously. There we go. So what I'm doing is I introduce an implicit conversion operator to person and this allows me to write the following. So I cannot keep using var, but I can write person, person and this will work just fine. So let's actually compile this and execute this. And as you can see, we're getting the built up person. So we have the address initialized correctly and we have the employment information initialized correctly as well. So this is a more complicated example. I recommend that you actually download this code and jump into it and figure out what's going on here, because there is a bit of a trickery in the way that we're we've essentially built a facade. So a facade is simply a component which hides a lot of information behind it. Now here we've made the classes of the sub builders public, but obviously, as you can imagine, you can make them inner classes of person builder, you can hide their internals from the consumer. That's also quite possible. So this is the faceted builder approach.