Lecture thumbnail 0:00 / 0:00 We’re now going to take a look at a design pattern called ambient context.

So what is ambient context all about?

Well, let me show you a very simple scenario.

Let’s suppose that you decide to model buildings using C sharp, so you have a class for building,

and that class has maybe a list of walls.

So I’m going to have a list of wall walls.

And then of course, we’re going to have a class for a wall.

So a wall is going to be composed of, let’s say, two points which determine the start and end positions

of the wall.

But the wall also has other attributes like the wall height, for example.

So we can have a bunch of points for the start and end of the wall.

And by the way, let me just define the structure for a point.

So this can be something like X and Y with a constructor to initialize everything like so.

And then in addition, the wall might also have, let’s say, the wall height.

So public int height like so.

And once again I’ll have a constructor which initializes all of these fields and we can start working

with this construct so we can, for example, make a house, var house equals new building.

So we’re going to make a new building and we’re going to add some walls to that building.

Now let’s suppose that on the ground floor, so on the ground floor, the height of the ceiling is maybe

only 3000.

So the height of the walls is going to be that value.

So we have house, dot walls, dot add, and then we make a new point.

So these are two dimensional points.

Let’s say we start at position zero, we make a point which goes to five meters horizontally and then

the height would be 3000.

And similarly, we can sort of duplicate this and we can have another wall.

And by the way, I forgot the wall constructor here, so this should be a wall constructor like so let

me just get rid of this, duplicate this once again so this could go into the Y direction.

Another wall, four meters in the Y direction once again with the wall height of 3000.

Because it would be really weird if the walls if the adjoining walls had different height.

So on the ground floor, the height of the walls is 3000.

But let’s move on to the first floor.

So on the first floor, maybe the height of the walls is 3500.

So we would do something very similar to here to what we’re doing here, except that the height here

would be, let’s say, 3500.

You could also have different sizes of walls, obviously, and that sort of thing.

So you define some walls for the first floor and then we come back to the ground floor.

Let’s suppose we want to define some more walls on the ground floor.

So once we go, we’re back on the ground floor with a wall height of 3000mm.

So here you would say maybe from, let’s say 5000, 0 to 5000, 4000.

So you would define yet another wall.

So the thing about all of these walls is that when you’re working with a particular group of walls,

the height value stays the same because for every given floor there is a single height value.

And it’s really annoying that we have to type it once again.

So one solution would be to make a variable wall height or just height, set it to 3000 here and then

set it to 3500 here and set it back to 3000 here and then just start using this variable instead of

these.

So we could just go ahead and do it like this, change it here, change it here and change it here as

well.

So this is a much nicer solution.

Now, what the height is, it’s what we typically call an ambient context because every single wall

has a height.

And for any group of walls, that height would typically be the same value.

So it’s kind of ambient, It’s present everywhere.

So the next question you might have is why do we even provide it as a constructor argument?

Why do we have to specify it?

Why can’t we just have some centralized location where certain values are kept and we can do this?

And this is actually what is meant by an ambient context.

So we can have a class called Building Context and we can have, for example, public static int wall

height.

So we can have a variable static variable static member called wall height and we can manipulate this

instead of the local variable.

Now typically this thing would be a singleton in the sense that you would not construct it, you would

not even bother constructing any instances of it.

Or if you did construct instances of it, they would be singletons.

We’ll take a look at how to construct those in just a moment.

But for now, we have building context wall height.

So instead of having this variable here, we can have building context dot wall height here.

And I’m just going to copy this and paste it for the assignment statements, and we’re going to get

rid of the constructor argument altogether.

So we’ll get rid of it here.

We’ll get rid of it here and we’ll get rid of it here.

Because now what we’re going to do is we’re going to set the height to building context dot wall height,

and we’ll get rid of this parameter.

So we are done.

We are now using the ambient context and whenever we need to change it, you just use it, you just

change it statically.

Obviously this kind of approach is not thread safe because if you’ve got several threads doing their

own thing, they would need separate contexts.

Typically they would need their own context to work on.

And there are obviously solutions to this because there is always the thread static attribute or the

thread local type that you can use for storing the context.

So that’s not a problem.

I’m not even going to discuss this because it’s it’s easy to implement basically.

But what I am going to discuss is coming back to this example so you can see that if we have the baseline

wall height as 3000, we can consider this change to 3500 to be temporary.

So what would be nice is some sort of scope, some sort of scope inside that scope that value changes

to 3500 and then after we exit the scope, the value changes back to what it was previously.

And the question is, well, can we actually build this sort of thing?

And the answer is, of course, yes, we can build this sort of thing.

It does give us a more complicated context.

So it does give us a building context that’s a bit more complicated.

Let’s take a look at how that would work.

So I’m just going to make it sealed to be explicit So this thing is going to be disposable.

And in addition, it’s going to store a lot more stuff.

So remember, we don’t just need to store a single value.

We need to store an entire stack of values because as you layer these as you have using statements inside,

using statements, you want to have a stack of these contexts all available.

One inside another.

So essentially we’ll have a the wall height is no longer going to be static.

It’s going to be an instance, but we’re going to have a private static stack of these building contexts

available.

So I’m just going to call it stack, not very imaginative.

So this is going to be just just a stack of these building contexts.

Now, when you construct the building context, first of all, I’ll have a static constructor and you

don’t see many of those everyday.

So we’re going to have a static building context where we add at least one value to the stack so that

we have some baseline.

So we have stack dot push.

Just make a new building context and if we have a proper constructor for the building context, let’s

say Seedorf, which initializes the wall height, we would specify the value of zero here.

So we make a building context and we stick it inside the stack.

So there is at least one value there.

And then of course, what you can do is you can add additional values and create create more of these

scopes.

So whenever you make a new building context, as we are doing here, we have we’re setting the wall

height, but we also need to add ourselves to the stack.

So here you would say stack dot, push this because you’re adding yourself to this, this stack of context.

This is how we get to keep every single one.

Now if you want to know the current context, you just have a static accessor building context current

which just peeks into the stack.

So Stack Peek just takes the top element and returns that.

That is our current context.

And when it comes to disposing, assuming that there is more than one element in the stack, we simply

pop the stack.

So if stack dot count is greater than one, then we do Stack.pop.

It’s actually unlikely that this will ever happen.

It’s unlikely that you’ll ever have a stack which is not empty at this point.

It doesn’t make much sense.

But just just for the sake of safety, I’ve added this if condition, so we pop the stack, we remove

the latest element and then current points to the one that we had before.

So what does this give us?

What exactly did we achieve from all of this?

Well, to demonstrate this, first of all, I’m going to add a couple of two string implementations

for things like point, for example, let me add two string implementation for point.

And we also going to have a two string implementation for a wall.

Let’s add that.

So I will just have it like this, for example, and we’ll have a two string implementation for the

entire building.

So here I will override two string.

And how are we going to do this?

Well, I want just every single wall inside the line, so I’ll have a new string builder, let’s call

it as B, and then for each var wall in walls, I’m going to append line.

Basically, I’m going to take the wall and take it.

Turn it into a string and return this to string.

That way we collect the entire thing.

So now we can print a building to the console, which is kind of nice because coming back to this example

now, the context here, the building context has to use the current.

So building context, the current wall height, and that is the value that we’re going to be manipulating.

But the way we’re going to manipulate it is as follows.

So starting let’s say at this position, I’m going to say using new building context where the height

is 3000.

So from now on, the height of every single wall that you make is going to be implicitly set to 3000.

And if you need this to be 3500 here, then you would do it like this using new building context 3500,

and then you work with that height.

And then this is no longer required because as soon as we exit the scope here, it’s going to return

to the previous value, and the previous value is 3000.

So let’s actually run this.

Let’s take a look at whether or not it actually works.

Okay.

So we’re not printing anything yet.

That’s.

That’s, uh.

That’s a bit sad.

Let’s.

Let’s actually write line house.

That’s a good idea to not forget your output statements when you’re trying to do a demo.

And here we go.

So we’re starting with the values of 3000.

So that’s the first two walls, and then the context switches to 3500 and then the context switches

back and we’re back to a height of 3000.

So this has been a demonstration of the ambient context design pattern.

Now, one thing I’m sure you’re wondering is how does it relate to the singleton?

And in actual fact, I’m sure you can guess building context is in fact or should at least be a singleton

in a particular thread, because if you have lots of threads messing about with this and building objects

at the same time, it’s not going to be particularly nice.

But it’s really up to you how you want to handle this.

So you can just have it implicitly assume that there is just one thread which performs the building

and so there is no problem.

Or perhaps you want to have a thread static implementation where every single thread which has a building

context has its own building context.

That is also a possibility.

Either way, it is a de facto singleton, however you look at it because well, concurrent accesses

don’t really make that much sense.

Play Play Play Play Play Play Stop Start Play information alert