Lecture thumbnail 0:00 / 0:00 The only thing which should be screaming in your head right now and you should be saying, But Dimitri,

at the beginning of the course, you told us about the open closed principle and you’ve just clearly

broken the open closed principle.

And you are right.

In fact, I have broken the principle by putting this enum in here.

Because think about it, let’s suppose that there is a third type of drink.

Let’s suppose that there is also a I don’t know what else hot chocolate.

Let’s suppose that we get hot chocolate and we need to implement the appropriate members.

Now there is no problem in taking a different assembly and implementing.

First of all, I hot drink.

So you have hot chocolate implementing the I hot drink interface.

Then you have the hot chocolate factory implementing a hot drink factory and everything is fine.

But unfortunately you have to go into an existing chunk of code and you have to add an enum member because

without this enum member, nothing, absolutely nothing will work.

So let me correct this slight violation of the open closed principle.

Not not so slight actually.

It’s actually quite significant in this case.

So what we’re going to do is we’re going to get rid of this whole enum approach.

We’re actually going to try and model this hot drinks machine in an interactive way.

So the way I’m going to do this is by basically commenting everything out and we’re going to do a slightly

different implementation of what we’ve just done above.

But without the enums.

And the way we’re going to do it is of course, by using reflection, because in the same way that we’ve

looked at the enumerated values here, what we can do is we can find every type in the current assembly,

for example, which actually implements the interface for an eye hot drink factory.

Now typically, and this is going to be on the scope of what I want to show here, typically you would

do this using a dependency injection container instead of just doing it by using reflection.

But I’m going to use reflection because it’s going to work and it’s going to show you how the whole

thing can operate.

So I’m going to make a new constructor.

So we’re going to have a hot drink machine constructor once again.

But this time round we’re going to do something different because I’m going to write a for each loop

where I will get all the types from the hot drink machine assembly.

So I’m going to say type of hot drink machine and I’m going to say assembly like so and I’m going to

say get types.

And there we go.

All right.

So in this case, let me just jump here.

I’ll call the type T, What we’re going to do is we’re going to check whether this type is, in fact,

an eye hot drink factory.

So I’m going to say if type of eye hot drink factory.

Is assignable from This is how you test whether something implements an interface.

Is assignable from T and we also have to make sure that we don’t get the interface itself.

So we say not t is interface because I hot drinks factory is in fact assignable from I hot drinks factory

fairly obvious stuff.

So we have to filter out the interface itself and then we do a different set of factories.

So for example, we can have something like the following.

We can have a private list of tuples.

I’m going to use the old fashioned tuples instead of a new C sharp seven tuples.

So we’re going to have a tuple with a string indicating the name of the drink as well as an I hot drink

factory.

So that’s going to be the list.

I’m going to call it factories once again.

So let’s just make a new initialized list, just an empty list here and here.

I’m going to populate it.

So I’m going to say named well, I’m going to say factories.

In fact, Dot add.

And here, first of all, I have to make a tuple.

So new table dot create.

There we go.

So here I have to specify the two arguments.

And the first argument is the name of the type that we just got with the factory part removed.

So I’m going to say t dot name dot replace and I’m going to replace factory with just string empty like

so.

And then the second argument is the I hot drink factory and we already have the type, we have system

dot type for it.

So using activator.createinstance is a lot easier because you just say activator dot create instance

and you specify the argument.

T and of course you have to cast it to an I hot drink factory should be fairly obvious because it returns

an object by default.

So this is an approach where it’s going to look in the assembly and find all the different types of

factories and add them to the list.

So now let’s complete this example by making a kind of interactive interface for making drinks.

So I’m going to have a public I hot drink, make drink, and we’re going to query from the user parameters

on what kind of drink they want and what what they want with it.

So I’m going to comment this out for now, by the way.

Okay.

So what are we going to do?

We’re going to first of all, list the available drinks.

So Writeline, I’m going to list the available drinks like so.

And then because I have a list of these tuples, I can go through that list and just print every element.

So I can say for each var, well, it’s going to be a tuple of some kind in factories, but in actual

fact I also want its index maybe so that the user can type in like 0 or 1 or whatever.

So I’m going to do a refactoring here.

Just press alt enter and convert it to a four instead.

I’ll keep this as index.

So here I’m going to write line, right line.

Let’s do it like this.

I’m going to write the index colon and then a tuple dot.

And since I use the old fashioned tuple, I’ll just use item one, which is the name of the drink that

you want to make.

Okay, so this is how you actually make drink.

We can actually test some of this output already, so I’m going to get rid of this completely and I’ll

say machine dot make drink like so.

Notice no arguments here.

I’m going to introduce a variable of some kind.

So it’s going to be called drink.

At the moment we’re just going to return null because we’re not ready yet.

But I want to show you that some of this is already working and we’re getting the drink.

So these values we’ve gotten from reflection by finding the appropriate factories, getting rid of the

factory keyword and adding them to our list.

So we have tea and coffee.

Okay?

So now we want user input.

So we want the user to specify what kind of drink they actually want.

And since the user input can be faulty because we’re expecting numbers and they might enter, I don’t

know, something else, something completely relevant, what I’m going to do is I’m going to put a while

true here.

While true like so.

Okay.

So first of all, we’re going to have some string where we read the data into.

So we say if s is equal to console dot write line.

So if we read the well, it’s actually read line here.

If we read a string and the string is not null, then we can actually try parsing the string into an

int.

So we can say and int dot try parse.

So we trying to parse the string s and we say we have out int i as the variable to parse into.

So if this succeeds, let’s get rid of the extra bracket here and the value is greater than or equal

to zero and the value is less than the total number of factories.

So factories dot count, then of course we can proceed.

So now we know what kind of drink to actually make.

So it can be tea or coffee, which would be 0 or 1 in this case.

And then we need to specify the amount.

So once again I can use.

Console.write to specify the amount.

And here we once again say s equals readline like so.

And once again we do a check.

So if s is not equal to null.

And we can parse it into some other variable in try parse s into out int amount.

So if we succeed in this and the amount is greater than zero, then we can actually prepare the drink.

And the way this is done this time is we return, we take the factories at the index, which is in this

case I.

So this is the first integer that we’ve passed Index I So we take the factory with index I, we take

item two, which is the actual factory and we call prepare on it, prepare with the amount which we

already have, we have parsed the amount as well.

And if all of this fails then somewhere towards the end of the while loop we can write line something

like incorrect input.

Try again.

Okay, so now that we have this kind of setup, we can actually not just get the drink but consume it

as well.

Okay.

So now that we’ve built this example, let’s take a look at how it works.

So I have two available drinks, zero and one.

I can make a coffee, for example, and here I can specify the amount as 100 and I get 100ml of sensational

coffee.

So this demonstration shows how you can kind of get around the open closed principle by basically using

reflection and typically in a kind of more serious, shall we say, application Instead of having the

objects being collected through reflection, you would have these objects automatically initialized

by the dependency injection container.

So you would have a ready made list for anyone to to actually present.

And when you alter this list by, let’s say you have a plug in architecture in your system where people

can add additional drinks and additional drink factories, then those will be automatically detected

here.

And when you call, make drink, those would be displayed as well.

So this is how you get around to not violating the open closed principle.

Play Play Play Play Play Play Play Play Stop Start Play information alert