Lecture thumbnail 0:00 / 0:00 All right.

So the first pattern of the two original gang of four design patterns that we talked about was the factory

method.

Now, factories themselves were not presented as a design pattern.

Instead, we have the factory method, which we’ve already seen, as well as the second design pattern,

which is called an abstract factory.

So why an abstract factory?

Why can’t we just be happy with ordinary factories?

Well, in actual fact, the only real use of an abstract factory is to give out abstract objects as

opposed to concrete objects.

So remember, in the previous example, what we had is we had a class and a class called Point, and

then of course, we had some sort of point factory.

So we had Point Factory and that point factory.

Whenever it had any factory methods, it returned a point.

So it had point, create whatever point.

And then that’s where we actually created the point.

Now, in an abstract setting, you are not returning the types you are creating.

Now, you might be wondering, well, hold on, if you’re not returning the types, you’re actually

asked by the client, what are you returning?

And the answer is you’re returning abstract classes or interfaces.

And this leads to the idea of an abstract factory.

Now, strictly speaking, in literature, people talk about abstract factories creating families of

objects, but that’s not necessarily the case.

We’re going to demonstrate it by creating not families of objects, but just two different objects with

their own separate factories.

And you can expand this idea to families of objects if that’s what you want to do.

Okay.

So let me show you a kind of setup that you might want to have.

So let’s suppose that we have a machine which makes hot drinks.

It makes tea and coffee, for example, but we want to give the user an ability to consume a drink without

holding onto its actual type.

So the user asks for a particular drink.

They might say, Well, I want a cup of tea, but we don’t give them an object of type tea.

Instead we give them an interface.

So for example, we can give them an interface called I Hot Drink.

And all they can do with this interface is they can consume it, so they can consume the actual object.

Now the actual realizations of this interface can have additional methods, additional properties,

whatever.

But we expose just this interface.

So for example, if I want to make tea, I can make an internal and here I’m using the internal keyword

to kind of simulate the fact that this class isn’t being given out to anyone.

So we have an internal class called Tea, which is an I hot drink.

So we simply implement the missing members and here we consume.

That’s the only thing you can do with the hot drink as a client.

So the client can, for example, if I import console again.

So let’s have using static system console.

What the client can do is the client can actually consume the drink.

So we’re going to writeline this tea is nice, but I’d prefer it with milk for example.

British people actually drink tea with milk, which is bizarre.

Anyways, we have this class and we might have an additional class.

So internal class coffee for example, which is an AI hot drink.

And once again we implement the missing members and here we’ll write line.

This coffee is sensational.

Quite a strong word.

Okay, so we have an interface for drink and we have two classes and they’re internal.

They’re not being given out.

No factory is going to return an tea or a coffee.

Instead, they’re all going to return an I hot drink.

So then let us suppose that for whatever reason, we actually want to have different factories for tea

and coffee.

Maybe the process is different and maybe the process is complicated enough that you want to take them

apart.

Or maybe instead of tea and coffee you have different classes of tea.

Like when you make a tea, you make either black tea or tea with milk or green tea or whatever.

And when you make coffee, you make filter coffee or a cappuccino or something else.

We’ll just stick to two objects, two types of objects that we make.

So instead of just making one hot drink factory, what you can do is you can once again make an interface.

So let’s make a public interface called a hot drink factory.

And in terms of what the factory of a hot drink has to do is it has to be able to prepare that drink

and return it.

So the return type is an I hot drink and the method is called prepare.

And we’ll have some argument here like the amount of volume that you actually want to have.

So this is the interface.

And then of course you can make the actual classes for the factory.

So once again, I can have an internal class called Tea Factory, which is going to be an I hot drink

factory.

Okay.

So here what I’m going to do is I’ll implement the prepare.

And here I’ll write line the process for actually making a cup of tea.

So you put in a tea bag, boil water, you pour a particular amount, which I’ll specify here in milliliters.

Add lemon and enjoy.

That’s it.

So that’s how you make a cup of tea and then you return.

And here we’ll just simulate return.

You see, Notice I’m not customizing the tea in any way in the real world.

You might customize it however you like by, let’s say, putting in the amount here, for example.

And here we’re going to have the second factor, which is going to be an internal class called Coffee

Factory.

Fairly obvious stuff.

Also an eye hot drink factory.

Once again, we implement the missing members and here we prepare the coffee.

So a very similar process, right line.

And here we grind some beans, boil water, we pour the amount in milliliters and what do you add to

coffee, cream and sugar and enjoy once again.

And then I’m going to return a new coffee.

There we go.

Okay, so now we have two factories which are internal.

So once again, we’re not giving out these factories to anyone.

And we also have the interface for an abstract factory.

Now, what does this give us?

Well, this gives us an ability to define a hot drink machine where the user can specify the drink that

they want, perhaps as enumerations and return the appropriate drink.

So let me show you how we can implement this.

Let me close this so we’ll have a class called Hot Drink Machine.

There we go.

So first of all, I have to define the drinks which are available.

So I’ll make a public enum called Available Drink.

It can be a list.

For example, if a machine runs out of something, it can be a list instead of an enum.

So I’ll just add coffee and tea here.

And then of course I will have a bunch of factories and this is where the abstractness of the factory

comes into play.

Because if you have an interface or indeed an abstract class, you can make a list of those things or

a dictionary, for example.

So I’m going to have a dictionary from this enumeration to the factory that can actually make this type

of beverage.

So here I’m going to make a private variable of type dictionary and it’s going to map an available drink

to an I hot drink factory, and I’m going to call this variable factories.

So this field is going to just be initialized with an empty value by default.

And then in the constructor, we’re going to actually initialize it with something useful.

So how do we do that?

Well, one of the ways is to just walk the enum.

And for every enum, like if you see an enum member called Coffee, you make a coffee factory and you

add it to the dictionary.

Fairly simple stuff.

So let’s do it.

So I’m going to say for each available drink drink in enum dot, get values.

So I’m going to get the values of available drink like so.

And then what I’m going to do is I’m going to grab the factory.

So I’m going to say var factory equals and then I need to cast it to an I hot drink factory.

But it’s going to be an activator call.

So activator dot create.

Oh, sorry, wrong location activator dot create instance.

As you may have guessed, we need to use create instance because we’re going to make the actual factory

by name.

So here what we need to do is we need to say type dot get, type like so.

And first of all, we have the namespace prefix to take care of.

So that’s design patterns.

So I’m going to put it in here, design patterns dot and then I’m going to take the actual name of the

enum members.

So that would be enum dot get name once again type of available drink.

And the second argument is drink.

That’s from the enum that we’re getting and then I also need to add the word factory towards the end

because that’s the final part for the whole thing to work.

So I’m going to add factory here.

Okay, so we have this massive activator create instance call.

Notice it’s being wavy underlined in case you don’t find the type.

But here I’ve kind of guaranteed to an extent that we can find the appropriate type.

So after we’ve made the factory, what we can do is we can actually add it to the list of factories.

So we say factories dot add and we add the key, which is drink as well as the factory.

So that’s pretty much it.

So in the hot drinks machine, what we’re doing is we’re just initializing everything and then here

in the main we can actually start using this hot drink factory to actually make something.

Well, it’s a hot drink machine.

I’m kind of implying that it’s also a factory in and of itself, but it’s it’s a different kind of factory.

So how do you make a drink?

Well, at the moment, since we are using this approach, the process of making a drink is really easy.

So let’s actually implement some sort of method for doing that.

So for example, you can have a public hot drink method returning method called make drink, and here

you can specify the available drink to make as well as the amount.

And here we simply grab the factory.

So we say return factories with the key of drink and we say Dot prepare and we prepare the drink with

the specified amount.

Okay.

So finally we can start using it.

So I can say var machine equals new hot drink machine.

And then if I want to make a cup of tea, for example, I can say var drink equals machine dot make

drink.

I can specify the drink type as tea and I can specify the amount as 100.

Notice that the kind of triple double in direction here two dots is not particularly nice.

But anyways, let’s do it for now.

So drink dot consume.

So we make the drink using the factory and we consume it.

Now let’s actually run this just just to see that it’s all working, that we don’t have any problems.

So we put in the tea bag, pour the water, pour 100ml, and then we can consume the tea.

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