Open-Closed Principle

Dmitri Nesteruk
A free video tutorial from Dmitri Nesteruk
Software/Hardware Engineering • Quant Finance • Algotrading
4.4 instructor rating • 20 courses • 104,639 students

Lecture description

A discussion of the Open-Closed Principle, which states that classes should be open for extension, but closed for modification. In other words, you should extend functionality using interfaces and inheritance rather than jumping back into already-written/tested code and adding to it or changing it.

Learn more from the full course

Design Patterns in C# and .NET

Discover the modern implementation of design patterns with C# and .NET

17:57:13 of on-demand video • Updated May 2020

  • Recognize and apply design patterns
  • Refactor existing designs to use design patterns
  • Reason about applicability and usability of design patterns
English [Auto] OK so we're now going to take a look and yet another principle from the solid principles on this one is called the Open Closed principle So what is this all about. Well once again I'm going to set up a scenario where we're going to violate the open closed principle and then we're going to rectify this and get the implementation which actually doesn't break open close so let me first of all show you a very simple demo. Now let's suppose you're building a ordering system maybe some web site where you can buy products and the products have certain categories and certain traits. So for example you might have different colors of products so you might have red green blue and so on products and you might similarly have an numeration for the size of the product how big it is so you might have small medium large Maybe huge if you're Donald Trump fan. So now that you have the setup you might have a class which actually implements these particular traits or not so much implements them as uses them to describe a particular product so we're going to have a class called Project. So the product might have a name that might have a name like so you might also have a color and you might have a size as well. And I want to keep all of these public by the way so I'm not making properties and said I was just making public fields which is completely legal in dotnet as you may know. So let's make a constructor where we initialize all of these fields. So this is the name the caller and the size and that's it for the product. Now let us suppose that somewhere on our wonderful Web site we want to be able to filter the kind of products that we actually get to see. And instead of using link to filter out a collection of products we're having to restrict ourselves to only filtering by certain criteria. Kind of like Amazon which doesn't let you filter by the actual rating anymore. So we're going to restrict the kind of filtering that you can do by using a product filter. So let's suppose that your boss comes to you and says Well how about filtering by size for example. So can you please ensure that our customers can filter the products by size so you implement a method for doing exactly that and you say public static I numerable off product please filter by XYZ or by Call it doesn't really matter that's how filter by size. So you specify a bunch of products I numerable products which is the products and you specify the size that you want. So the obvious output of this is that you go through each of the products. So for each var P in products you say if P matches in terms of the size Pido size is equal to size then you'd return. P That's really pretty much it. Now with this kind of setup you can already start using it for certain things in the sense that we might want to do a scenario now so I'm going to make a couple of products. I'll make an apple which is going to be a new product which is called the Apple obviously its color is green and its size is rather small. OK. In addition we'll have half a tree. You might go to a gardening store and buy a tree so that's going to be a new product on the string. So I was going to be a product called a tree and it's also green but its size is rather large. And in addition we'll have a house which is yet another product like so so that's a house it might be blue instead of green. So I was going to be a blue and also a large item. OK. So these are the three items we can make an array out of them or some other kind of I numerable but I'm going to go with an array here so I have a product or a called products and that's where we're going to have the apple tree and house. And then of course once you start using that filtering functionality. So I make a product filter of RPF because new products filter. And let's suppose that I'm looking for all the green products. So what I can say is I can write a line for example green products and that's going to be I'm going to say old because that's going to be the old way of doing things. But you'll notice that so far we don't have any filtering by color we only have filleting by size which isn't what we want. So in order to implement this new functionality we unfortunately have to go back into the filter and we have to modify the filter. So we have to take this code. We can duplicate this. And we need to filter by color this time around so filter by color. And here we specify color color and then of course this check becomes P-doc color is equal to color. There we go. So now that we have this we can actually start using it on the product so we say for each var P in P.F. filter. So in this case we have to make it public or actually it is already public because it's just has to be filtered by color here so we specify the products and we specify that color as green for example. So we want to find all the green items and when we do find a green item then by the way let's see what's going on here. So we'll make it oh it's non-static. Let's keep these things no static for for now and I'll get rid of this thing here as well is really up to you. It can be static if you want it to. So for now we filter the items by color. We can write line. The information about the item. So I just put in-dash here. So I'm going to say Pido that name is green and we can actually execute this and see what we get. So we're getting the right input happily is green tree is green everything is fine now. Unfortunately what happens now is your boss comes back and the boss says well now you're going to filter by both sides and call it you're going to let people specify both the size and the column you want to search items by. So this is a bit of a problem because now once again you have to open up product filter you have to jump into that class and you have to add yet another piece of functionality so this time round it's not just a simple application and renaming it's a bit more. So we're going to filter by size and color. And if you want to filter by size and color you have to specify size size color color and then you say Pido size is equal to size and color is equal to color. So this is how you implement this. And then of course you can start using it. And this whole thing everything that I've shown right now happens to break the open closed principle because the open closed principle states that classes should be open for extension which means it should be possible to extend the product filter. It should be possible to make new filters but they should be closed for modification which means nobody should be going back into the filter and actually editing the code which is already there because we can assume that the filter might have already been shipped to a customer. Now how can we extend things without actually going back and changing their bodies. The answer is of course inheritance. The answer is that you can implement interfaces thereby extending the capabilities of the system. So instead of having this brute force approach all we can do is we can implement a pattern and that's going to be a new thing for us. We haven't actually done any kind of patterns before and now we're going to implement a pattern but not a gang of four pattern. Instead we're going to implement what you might call an enterprise pattern called the specification pattern. And this is precisely the thing that will allow us to avoid violating the open closed principle. So how are we going to do it exactly. Well instead of having this rigid functionality we're going to make a bunch of interfaces so let's have a bunch of interfaces. And the first interface that we're going to make is going to be called specification now specification implements the specification patent which basically dictates whether or not a product satisfies some particular criteria. So you can think of this specification as a kind of predicate which operates on any type T. So notice I'm keeping my options here. I'm basically saying that you know an ice specification can work on virtually anything. So here I can specify the only method which will be required by anyone implementing a specification and that is a method called is satisfied. So what's happening here is with saying that we allow people to make specifications and we check whether a particular item of type T is actually satisfying some criteria and that we're not specifying the criteria here we're going to do it in just a moment. Now the other side of the puzzle is another interface and this one is going to be called an I filter now and I feel there is precisely a filtering mechanism but there's a filtering mechanism which once again operates on any type T. So we take a bunch of items of type T and lifter according to the specification which is defined here. So the interface is that you return an AI and numerable off t and you basically filter a bunch of I numerable of the items by numerable off the items given the appropriate specification given specification of T which I'm going to call spec. So this is the interface you feeded a bunch of items. You tell it what the specification of those items should be and how to filter them and you get a bunch of filtered items back. So now we can implement everything that we've done up until now using spec.. And I filter as well. So let me show you how to make a specification for color lets suppose you want to filter items by color so you make a color specification. So it's a very simple thing. This would implement an AI specification. And once again the types here can be virtually anything but we're filtering products right. So we are working with products we're working with something else though we might be. So we see that we implement a specification of product that we go. So let's go ahead and implemented the missing members. And here we need to have a definition for the color we're going to filter by. So here I see color color like so I can initialize it in the constructor and then to check whether the code specification is satisfied I simply return that t that color is equal to color. Just like that. All right so this is a color specification we can now do the same kind of green products filtering but we can do it in a much nicer way. So for that we need another piece of the puzzle which is of course a new functionality for filtering products because remember we made this interface. I filter but we haven't implemented it yet. So that's what we're going to do right now. We're going to make a better filter. So here's a class called better filter which is an eye filter off products because that's what we're filtering so let's implement the missing members here and now the implementation of this particular class is very trivial because all we do is we go through each of the items in turn. And if indeed the item satisfies a particular specification so if the specification that we provide is satisfied by the item by then we would return that item. That's pretty much it. That's all you have to do to make the better filter work. But now let's take a look at how to actually use it. So far B-F equals better filter like so we'll write a line here that we're getting green products once again but this time using the new filter. And then of course I'll do another for each Vark P in and here we use the better filters so BFD that we say filter and then we have to provide both the items as well as the specifications so the items is products as before. But for the specification we'll make a new call a specification where we specify that the color should be green and then we can output it just as we did previously. So just copy this over. All right. So this is an identical way. And of course it gives us identical results which is exactly what we wanted. All right so now you might be wondering. OK this was color. Now how about color and size. How about filtering by both of these for example. So first of all we have to make a size specification so once again I'll make a size specification which is an eye specification of the product. And here just implemented the missing members here we specify the size. We might provide it in the constructor for example. And then when you want to check whether it's satisfied you return Titos size is equal to size so that's fairly easy. And now what we can do is we can filter items by size in the same way that we've done here. So now coming back to the question what if you want to filter by both size and color as well. Well this is actually possible using a combinator which is also going to be an eye specification of something or other. So to take a look at how to build one. So I'm going to make a class called and specification so this and specification and it's going to be a generic one is going to be an AI specification of T. So we're keeping things generic that we're not really doing anything in terms of categorizing and saying oh this is going to be only for products and nothing else is going to be a very general thing. So the idea is that the specification will actually take two specifications like a color specification and a size specification and they will and then together in that is satisfied. So one of the ways of doing it is you simply specify I specification the first and second you might want to make a constructor which actually initializes both of them. You may as well use some C-Sharp 7 features here if you want so you can sort of like this. And for the second one as well. So the double question marks. And then of course when it comes to checking whether it's satisfied simply return whether the first specification is satisfied by T and the second specification is satisfied by the. All right. So having made this let's take a look at how we can find for example the old the large blue items. So let's write a line here large a large blue items like so and then for each Vark P in better filter Daut filter. Ok so now we need to make n and specification so new and specification which has to provide a name in particular have to provide a type. And here we're going to have the two arguments. So the first argument and by the way we forgot products as the first argument here. So the first argument is product and the second is and specification. And we need to specify the color specification here. So the color has to be blue. And in addition the size specification where the size has to be large. So we're looking for a large blue item or a set of items in fact. So this is how you would make a composite specification using a combinator. And here we can go through the items and once again we can line the actual items so we can say P-Dub name is big and blue like so. And of course when I run it I get the house. So the house is big and blue. So this has been a demonstration of the open closed principle just as a recap the open closed principle states that parts of the system or in the subsystems have to be open for extensions so you should be able to extend the functionality of a filter for example but they should be closed for modification so you shouldn't have to go back into better filter for example and start adding things right here you shouldn't be able to do that. Instead if you want more functionality you make new classes you implement specification and you feed those into something that has already been made and something that may have already been shipped. You don't want to we ship the functionality of pedophiles to customers but you can ship additional modules which implement a specification and which make use of better filter. So that is what the open closed principle is all about.