If you learned something new feel free to connect with me on linkedin or follow me on dev.to :)
Hi there, in this post I'd like to talk about some common coding patterns that I really wish I knew when I had started my career 5 years ago.
A bit of a disclaimer first though, my career is all over the place. In those five years I have: started my own company, worked on large scalable applications, developed many POC's and I even did some APIM administration for a while. As such I've seen many of the same coding patterns get repeated over and over again. Here are some that I defiantly think that you should understand if you are starting out in your career.
Also if you want to jump into some code samples I have left a link to the GitHub project here.
On my old blog I wrote about many more patterns then I have gone through here in this post which is why there are so many in the repo.
Abstract Factory/ Factory Pattern
Essentially you use it when you want to instantiate objects from the same family of objects. Simple to say, easy to do... ish.
The main reason for using is to help with testing. Ideally the factory itself would be injected into the object that is going to make use of it. The objects that the factory creates would need to inherit from either an interface or an (wait for it...) an abstract class. Here is a uml diagram that goes through how this all fits together:The main difference between the abstract factory and the regular factory is in the abstraction of objects used. One has it the other doesn't. On to the code :), after all that's what we are here for.
The first step is always to define the objects that we will be instating in our factory. This is done by implementing an interface. The concrete creation of our objects will be done in the abstracted factory. The second step is to define our factory. This again will be abstracted away so that it can be injected in when needed.Next on to testing so that we can prove our stuff works.Cool it works :) and there you have it an abstract factory that can be injected and used for creating objects. Neat!
Have you ever had one of those moments where you need to have just one instance of an object and pass it around. Like a Frisbee? Well then the singleton pattern is the right one to use. It is an object where, yeah I've already explained. One and only one instance. Now inside of this pattern there are a few different ways of constructing it.
- Regular (normally creates the object on start-up)
- Lazy (this is used to create the object when it is first being used)
Here is a diagram of how it all fit's in together:The very first thing that we need to do is to create an interface to abstract our object.Our next step is to turn this normal everyday class into a singleton. We do this by creating an instance of our MySingleton class inside of our MySingleton class (Singletonception...). This makes sure that there can only ever be one instance of this object as static objects point back to the same reference point in memory.WOW!! Big changes essentially by creating an instance of a static object we have. Wait for it... we made sure that there is only one instance of the object. We can now call MySingleton.Instance to essential pass around the object. Neat! But... we can be lazy, which in this context is fantastic. Basically what we have done with creating an instance of a static object is created an object way, way before we may need it. Program executes... baam, object created. This is less than ideal, so we are going to be lazy about it (pun intended).By creating the object lazily we have said is that when, we first need the object create it. Instead of you at the start when no-one needs it. At all. Full stop.
The line "static Lazy instance = new Lazy(() => new MySingleton());" looks scary but, essential all that we are doing is creating a new lazy object of type MySingleton and then when instance first gets called, create a new instance of MySingleton.
And there you have it. A lazy loading singleton.
Essentially this pattern is used when you need to build up a large and complex object. Instead of passing in all of the parameters at the beginning (Don't do it, try to stick to three-four at max). This pattern enables you to create a complex object bit by bit, to separate away the hassle of trying to manage a large constructor/ method signature.
Here is a diagram of how the pattern is constructed:This project is a little in-depth. So we need a situation. Our client is a Car manufacturer that needs us to help them build cars. First off lets design our car object and our builder's interface.
Codeward we go!!Cool, now on to implementing our builder and creating our client, that will encapsulate our builder.Great, what we have done is created a builder that builds our Car and a client that oversees the build process. So what now, well now we see how to implement it. The important part of this bit of code is in the cloning/ clearing of the built Car before it has been returned. The reason for this is that now, the constructor doesn't have to be called again to start of with an entirely new Car.Simples! Right well... sorry to break it to you but, we can improve on this by making it fluent. What's fluent I hear you ask. This basically means that we are going to be chaining our build calls together so that it's not so disparate. And there you have it job done. A builder object that can be used to build objects.
The adaptive pattern is all about converting one interface/ object to another. Simple as...
Here is a diagram of how it all works together.Target (ITarget): This defines the object that the client is expecting to get.Adaptee: This is the object that needs to be adapted.Adapter: This object holds a reference to the adaptee. It is responsible for converting the adaptee methods into ones that the client expects to see.Here is an example of how this pattern can be implemented. As you can see our client class is only compatible with the ITarget interface and not the Adaptee.
First of, this pattern is used for when you want to change the behavior of an object without extending it. This is done through the use of a context object that holds a reference to an implementation of IStrategy. Here is a diagram to explain what it is:Context: This class is used to access and call the DoSomething method of our strategy objects.StrategyA/ StrategyB: Theses classes are children of the IStrategy interface and where the core functionality is held.As you can see from the image below, when we change the IStrategy object the behavior of the Context object changes.
I really do hope that this helps someone out or you learn something new from it. For me when I was starting one of my biggest failing was not knowing the names of the patterns. Sure I had used some of them before but, no one ever told me the name of them. It made for some... interesting interviews to say the least.
Thanks for reading my post and I hope to see you in the next one!