8 Design Patterns EVERY Developer Should Know

Download information and video details for 8 Design Patterns EVERY Developer Should Know
Uploader:
NeetCodePublished at:
2/6/2023Views:
1.2MDescription:
🚀 - A better way to prepare for coding interviews! Checkout my second Channel: @NeetCodeIO While some object oriented design patterns are a bit outdated, it's important for every software engineer to understand the most important ones. I cover several of my favorite ones in this video. Code from video: 🧑💼 LinkedIn: 🥷 Discord: 🐦 Twitter: 📷 Instagram: 🎵 TikTok: 0:00 - Intro 0:45 - Factory 1:35 - Builder 2:23 - Singleton 3:38 - Observer 5:12 - Iterator 6:28 - Strategy 7:18 - Adapter 8:22 - Facade #design #patterns #python
Video Transcription
I heard you liked factories, so I made you a factory inside a factory which inherits from an abstract factory so it can create new factories.
But enough about programming in Java.
In this video, we will learn about eight design patterns every developer should know.
In 1994, the Gang of Four released the Holy Book design patterns, introducing 23 object-oriented design patterns falling into one of three buckets.
Creational patterns, structural patterns, and behavioral patterns.
While some argue that it's dated, the fact that a 30 year old book is still being discussed definitely means something, especially in a world where JavaScript frameworks are going out of style faster than you can say JavaScript was a mistake.
Anyways, let's start with our first creational pattern, the factory.
Imagine that you want a burger, but you don't want to have to worry about getting all the ingredients and putting them together.
So instead you just order a burger.
Well we can do the same thing with code.
If it takes a list of ingredients to create a burger, we can instead use a factory which will instantiate the burger for us and return it to us whether it's a cheeseburger, a deluxe cheeseburger, or even a vegan burger.
All we have to do is tell the factory what kind of burger we want, just like you would do at a restaurant.
But be careful because this way you'll never know what's inside the special sauce.
We added a secret ingredient.
It's semen.
Now, alternatively, if you want a little more control over how the sausage is made, you can go with the builder pattern.
The idea is that if we want to make a burger, we don't immediately have to pass in all the parameters.
We can use a burger builder instead.
We'll have an individual method for adding each ingredients, whether it's a bun, patty, or cheese, each one will return a reference to the builder.
And finally, we'll have a build method, which will return the final product.
Then we can instantiate a burger builder, add the buns that we want, the patty that we want, and the cheese that we want.
And we can chain these methods because remember, each one will return a reference to the builder.
Finally, we can build it and we have the exact burger that we want.
I've used this pattern a lot at Google with protocol buffers.
Next, we have the singleton pattern, and I'm not talking about my dating life.
A singleton is just a class that can only have a single instance of it that's instantiated.
It has many use cases, for example, maintaining a single copy of our application state.
we would start by having a static instance variable.
Let's say in our app, we wanna know if a user is logged in or not, but we won't use the constructor to actually instantiate the application state.
We'll use a static method called getAppState, which will first check if there's already an existing instance of our application state.
If not, we'll instantiate one.
If there already is though, we'll just return the existing instance.
We'll never create more than one.
So now if we get our app state for the first time, the logged in value will initially be false.
But if we get the app state again, this will actually still be the first instance.
So if we modify the first instance and then print the logged in value for both of them, they will both now be true.
This pattern can be useful so that multiple components in your app will have a shared source of truth.
But how can all the components listen for updates in real time?
Well, that's where the observer comes in, our first behavioral pattern.
I prefer to call it the PubSub pattern.
It's widely used beyond just object-oriented programming, including in distributed systems.
Let's take YouTube for example.
Every time I upload a video, all of my subscribers get a notification, including you, because you're subscribed, right?
But in this case, the YouTube channel is the subject, aka publisher, which will be the source of events, such as a new video being uploaded.
We might want multiple observers, AKA subscribers to all be notified when these events happen in real time.
One way to implement this pattern is to have a YouTube channel class, which maintains a list of its subscribers.
When a new user subscribes, we add them to the list of subscribers.
When an event occurs, we go through that list of subscribers and send the event data to each of them with a notification.
But we also have to define the subscriber interface, which you can do with an abstract class or an interface.
Different subscribers might implement this interface differently, but for a YouTube user, let's say that we just want to print the notification that was received.
So then we can create a YouTube channel, add a few subscribers, and we only have to call notify once and all of the subscribers will receive the notification.
This is also extensible enough that a subscriber could be subscribed to multiple channels.
An iterator is a pretty simple pattern that defines how the values in an object can be iterated through.
In Python, just defining an array and then iterating through it with the in keyword uses the built-in list iterator.
This way we don't even have to index the array.
Now for more complex objects like binary search trees or linked lists, we can define our own.
We can take a list node, which just has a value and a next pointer, and then a linked list, which has a head pointer and a current pointer.
We can first define the iterator with the iter function, which will just set the current pointer to the head and then return a reference to the linked list.
To get the next value in the sequence, we define the next function.
If our current pointer is non-null, we can get the value and then return it and also shift the current pointer.
But if we reach the end of the linked list, we can send a signal that we're going to stop iterating.
To test it out, we can just initialize the linked list and iterate through it with the in keyword.
This is a much more simple interface than having to actually update pointers ourselves.
Now if you want to modify or extend the behavior of a class without directly changing it, you can go with the strategy pattern.
For example, we can filter an array by removing positive values or we could filter it by removing all odd values.
These are two strategies, but maybe in the future, we want to add more and we want to follow the open closed principle.
Well, we can define a filter strategy, create an implementation, which will remove all negative values and an implementation, which will remove all odd values.
And then at runtime, we can pass this strategy into our values object.
And to test it out, all we have to do is pass in the strategy into our filter method and we'll get our desired result.
This way we can add additional strategies without modifying our values class.
Next we have the adapter, our first structural pattern.
It's analogous to the real world where we have a screw that's too small to fit into a hole.
So instead we use an adapter which makes the screw compatible with the hole.
Or maybe an example that you're more familiar with, we have a USB cable and a USB port.
We can plug in the USB cable which will directly fit into the port.
But instead, if we have a micro USB cable, it's not compatible.
So instead we need a micro to USB adapter, which extends from the USB class, but is composed of a micro USB cable, which will be plugged into the adapter.
We can override the plug USB method from our parent class if needed, but it's not in this case.
And then we can plug our micro USB cable into the adapter and then plug it into the port.
And it works just like a regular USB cable.
And our last pattern is the facade.
According to the dictionary, a facade is an outward appearance that is maintained to conceal a less pleasant or credible reality.
In the programming world, the outward appearance is the class or interface we interact with as programmers.
And the less pleasant reality is hopefully the complexity that is hidden from us.
So a facade is simply a wrapper class that can be used to abstract lower level details that we don't want to have to worry about.
I'm surprised it even qualifies as a design pattern.
But some common examples might include HTTP clients that abstract away low-level network details, or even arrays.
Yes, a dynamic array like vectors in C++ or array lists in Java are constantly being resized under the hood.
Thankfully, as programmers, we rarely have to think about memory allocation though.
If you're interested to learn more, check out my newly released object-oriented design interview course.
We tackle some popular interview questions.
I've included video lessons, written articles, and code for four languages, and I'll be sure to add additional lessons in the future.
Thanks for watching, and make sure to subscribe, please.
Similar videos: Design Patterns EVERY Developer Should Know

The Art Direction Playbook for Filmmakers (+ Best Tools To Use)

Дизайн сайта

5 essential apps that help me stay focused on Windows 11

ПРОЩАЙ СТАРЫЙ BLENDER 5.0 #blender

Красивый графический интерфейс на Python | Все фишки Flet

