Faceted Builder

Dmitri Nesteruk
A free video tutorial from Dmitri Nesteruk
Software/Hardware Engineering • Quant Finance • Algotrading
4.5 instructor rating • 21 courses • 168,278 students

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:11:50 of on-demand video • Updated September 2021

  • 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 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 in Eilat 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, will have some employment information as well. So we have public string company name and position, and I led another field public int annual income, for example. So this is quite a bit of information on the person. And we want to well, first of all, we want to output this information. So I'll add formating members. I was just dump everything here. So we have a nice big to a string implementation so that 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 Fassett, or in fact, we're going to have to build our facets of Fassett 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 cedella 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. He was a 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. They can be mitigated, but I'm just putting it out there so that you're aware of this. 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 the 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 standalone, it also inherits from person builder. Now, this is really weird. Why are we inheriting from it? You 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 general menu, make a constructor. But I'm going to take a person person I'm going to assign this this the person he calls person like. So now what's happening here is that you're 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 a field and then we return this sort of person 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 will 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 a 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 the 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 at. And you can provide the company name com recap, for example, and then I can go to the next line and just indented nicely as a and I can say he works as an engineer. And then earning, let's say, one hundred and twenty three thousand rubles, for example, notice as soon as I put the semicolon, Bishop a reformats, the whole thing. So that kind of ruins the presentation. I'm going to undo it for now. OK, 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 of what I'm going to do is I'm just going to paste in a person address. So here we go. Person Indra's builder, very simple. It also takes the person reference. And I have to stress once again, this listing 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. OK, so what does this give us? Because you can see that we once again have a fluent interface. We have a method called AD. So the person lives at the street address with post code, so and so in such and such and Sydney. 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 at 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 not just 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 personal lives, lives dot lives forever. That's completely fine. But, you know, that's just a side effect of the fact that you are trying to make things convenient to use. So what we've done is we've used to sub builders to present a fluent interface for building up a person. But interestingly enough, if we now right line this right person, we're obviously not getting a person at the end because a 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 B and I simply return Piddock person. OK, 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 kind of keep using far, but I can write person person and this will work just fine. So that'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. We have the employment information initialized correctly as well. So this is a more complicated example. I recommend that you actually download this code than 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.