Lecture thumbnail 0:00 / 0:00 Okay, So the premise of the visitor pattern is that you have a requirement of adding functionality
to a hierarchy of types.
So here we have expression and double expression and addition expression.
And let’s suppose that neither of these types has a print method in it, and we are faced with having
these types already predefined for us and we need to add print functionality from the outside.
And the question is, well, how do we actually do it?
How do we add print functionality to every single type?
Now one approach, which is fairly obvious, is you simply make a separate component which uses reflection
to figure out which expression it’s actually printing.
So let me show you how this can work.
So I’ll make a static class called expression printer.
Expression printer.
Now the idea is we want to print any type of expression so we make a public static void print method.
And that’s going to be the only method in this class.
And this print method takes an expression.
E And then it takes a Stringbuilder Stringbuilder SB And we want to find out how to actually print the
particular expression.
Now the problem is that you now need to test this poor expression against every single type that you
have in the hierarchy.
So you start writing things like the following.
You say if E is double expression, d, e if this is indeed the case, then you do sp dot append the
e dot value otherwise.
And notice there is a bit of a problem here.
Up until now, value was private and we didn’t have to expose it.
But now of course what’s happening is since you need to access it from the outside, it has to be at
least internal and possibly public.
So let’s actually fix this.
First of all, I’ll go back to value.
I will make it public, but then it’s a public value.
So the naming convention changes and we now rename it to value with a capital V, and the same goes
for the addition expression.
So we say else if E is addition expression A, E, and then in the case of the addition expression,
we have to handle it using the whole business of multiple appends and recursive calls to print.
So it would look something like this.
Of course, here once again, the same problem we haven’t exposed left and right up until now.
But now we need to.
So they have to be, first of all, a left and right lower case and then we make them public, make
this public as well.
And then, of course, I will have to rename them to make sure the naming convention is correct.
So it’s going to be left with a capital L, and the same goes for.
Right.
So now we have a couple of public fields.
You might want to refactor those into properties later on, but the end result is that you would have
a massive if statement or indeed a massive switch statement if this is how you want to go.
But the whatever you do, the operation is now slightly different because what you need to do is you
need to call expression, print, dot print.
So that’s what we’re going to do here.
We’re going to say expression, printer, dot print.
And then you specify the expression you want to print.
Notice it’s using the base class expression, then you specify the stringbuilder.
But the end result here, if I go ahead and execute, this is exactly the same.
The end result is absolutely the same, even though we changed the mechanics.
So instead of having the print functionality inside the hierarchy, what we’ve done is we’ve made it
as a type where you perform a switch effectively on the different subtypes of expression that can be
and you print the appropriate results in the appropriate way.
So once again, hopefully this is obvious to you.
There are problems with it because first of all, you’re breaking the open closed principle.
Any time that there is a new type of expression, you have to go into the expression printer and you
have to add another else if whatever here.
And if you fail to add this elseif, then you’re going to have a no op, you’re not going to crash.
Luckily, you’re not going to generate an exception, but you will get certain functionality not working,
meaning that if your expression is of type subtraction expression, for example, nobody is going to
print anything.
So that’s something to watch out for.
Now there are ways of making this more palatable.
So if you don’t have a particular liking for if else or switch statements, what you can do is you can
make a table.
So it is quite realistic to make a table where you’re still using reflection, by the way, you’re still
casting to a type and checking that it’s of the right type, but you can do it differently.
So in order to do a reflection based table, what you need to do is, first of all, you need to define
the type of that table and it’s going to be a really ugly type.
So I’m going to put it here as a using.
Unfortunately, I have to do this at the top of the file.
I can’t just do this in any location where I want, so I’m going to have a dictionary type.
And this dictionary type is going to be a dictionary of and it’s going to map a type as in a system
type to an action which takes an expression as stringbuilder.
So this is my dictionary type.
And the reason why I’m making this is so I don’t have to type this whole thing twice because unfortunately
you cannot use Var in field declarations.
So too bad.
So instead of implementing print like this, what you can do is you can implement print slightly differently.
Let me show you how you can do this.
So with this dictionary type, which we call dict type, what you can do is you can say private static
dict type actions equals new dictionary type like so.
And then we can initialize a mapping from every type that we want to handle to a lambda, which in this
case is a system action taking.
An expression that the stringbuilder which actually handles whatever it is that we need to do.
So here, for example, I can say typeof double expression.
Is going to be handled by a lambda, which takes the expression as well as a stringbuilder.
And here, unfortunately, we cannot do a one liner.
We have to have curly braces here.
And the reason for this is that the action takes an expression and we need a double expression here.
So the consequence of this is we say var D equals double expression, E, and then with the double expression
we can say SB dot append, dot value like so.
And similarly for the other case.
So the other case is of course the addition expression we say typeof addition expression equals and
then e comma SB And this goes to.
Now here we need to copy this whole thing that we’ve made down below.
So let’s go down here and I’m just going to copy all of this.
I’ll paste it here, uncommented like this.
And then of course some of the print calls should be done differently.
But let’s cast it first of all.
So we say var e equals addition expression, expression E So we cast it to an addition expression,
and now the print calls, well, we’re still going to have the same print API, so let’s leave it red
for now.
Now the implementation of print in this case would be very similar.
It would be public static void print.
I’m actually going to copy this signature from here because it’s identical, but the implementation
is slightly different because what we do whenever somebody wants to print an expression, E is we look
at the actions where the key of the action is the type of the expression.
So we use actions at key dot get type, and then we invoke it because it’s an action and we specify
the expression as well as the stringbuilder.
So this is how you can avoid doing a switch or an if by making a dictionary instead.
It doesn’t really change anything in the sense that, you know, if the type is missing here, of course
what will happen is slightly worse than an if statement and an if statement.
If a type is missing, then nothing happens.
It’s an op.
Whereas what’s happening here is you’re going to try to get a key from a dictionary that doesn’t exist
and you’re going to get an exception.
So I in a way, I’ve made things worse.
But the point is, this also works.
It gives us the same exact result and it looks slightly neater at the expense of possibly generating
exceptions.
Depends on whether you want to see exceptions or whether you want to fail quietly.
So this is how you can implement an expression printer.
And it’s still not the visitor pattern.
It’s still not the classic visitor pattern.
It does work to an extent, but as you can see, coming back to the expression printer every time and
adding another line in here or another line sort of in the if is also inconvenient.
So we’re going to look at something which is more generic, especially when you consider the fact that
here we have a single expression printer.
But what if you want some other printer instead?
You would end up having to replicate all of the structure with all of the classes and it’s just too
tedious.
Maybe there is a better way out there.
Play Play Stop Play Play Play Play Play Start Play information alert