Transcript for:
Understanding the Decorator Pattern

it's time to talk about decorator pattern if you're new to this playlist I just want to quickly tell you that what we're doing is that we're walking through all of the patterns in this book head first design patterns one by one by one so in total there will be something like 12 to 13 to 14 videos because we'll split some of them into multiple videos so if you're not already subscribed to the channel be sure to subscribe to the channel so that you won't miss the next pattern but now a decorator pattern so before we go any further I just want to warn you that the example that's found in the head first book is in my opinion not really suitable for a decorator pattern in other words it's a good example for illustrating how decorator pattern works and how you sort of syntactically string the pieces together but I don't think and people are free to disagree but I don't think that it should be taken literally I don't think that the example that they report is actually a sensible use case for using decorator pattern we'll return to that but I just want you to remember that as we go through the example and in the end I'll give you some examples of what I find to be more suitable use cases for decorator pattern and when I've actually used it in real world scenarios while coding myself but now what is actually decorator pattern let's start on a high level I think it could be explained in multiple ways but here are two so the first one is decorative pattern essentially is about you having an object and instead of Simply sending messages to this object this could be speak you send the message speak and you expect the object to return for example a string back so you send the message speak and the object returns it responds s with the string hello world now decorator pattern is a way of saying that if I want to change the thing that's returned if I want to change the behavior of this method I could actually do that at runtime without changing the contents of this particular object so you change it at runtime and not at compile time and when we say change at runtime and not change at compile time you can simply think of that as changing the behavior of this thing without actually rewriting the contents of this thing without without actually opening up the class and changing the contents of that file so with decorator pattern what we do is instead that we say let's actually wrap this object in another object I'll remove these arrows and when I send the message speak I'll send the message to the outer object who will send the message to the inner object who will send the message out back to the outer object who will return it back to me and we can keep on doing this indefinitely and this is the essence of The Decorator pattern you can take another object you wrap this wrapped object you wrap the wrapper in another wrapper so another object that sends the message to the inner wrapper that sends the message to the inner object that then returns to the inner wrapper that returns to the outer wrapper and then returns back to you so it's seems kind of convoluted but you'll see why this is actually very valuable so you have an object that wraps another object that wraps another object and the point here let's move to the second explanation is that so you have the object in the middle and we'll refer to this as the component but this one the the one wrapping the component is a decorator and the one wrapping The Decorator is a decorator if you just think about a single one of these decorators The Decorator has a component and is a component we're going to get back to this but essentially remember that from the beginning we said that I take this original object and I want to send the message speak and then I'll get something back and now that we've wrapped it in in two decorators these two decorators actually behave from the outside from the interface standpoint they are as in Isa they are of the same type as this thing in other words they are exchangeable so whenever you have this thing you could use this thing instead or you could use this thing you wrap the original object and then you can use the wrapper and pass that around as if it was one of these original things so the first time I heard the sentence it is a and has a of the same type it kind of blew my mind I'm like what is this crazy pattern and actually it's kind of cool it's very similar to composite pattern that we'll talk about later but composite is sign iFly more complicated but you can think of it this way The Decorator is of the same type as this because you want to be able to treat it as if it was one of these things that's similar to proxy pattern that we'll talk about later and and the ha a portion the fact that it has one of these types is because you want to be able to send the message downwards and then back up that's why it has a but enough with the abstract nonsense let's get into something more concrete so let's look at the definition from the head first book by the way if you're new to design patterns I highly recommend you to get this book the link is in in the description it's an affiliate link so if you use that link I'll get a kickback and if you do thank you that helps massively but now moving on so here's what they say The Decorator pattern attaches additional responsibilities to an object dynamically decorators provide a flexible alternative to subclassing for extending functionality let's break this down The Decorator pattern attaches additional responsibilities to an object okay so that means this object was originally doing something but now using decorator pattern we attach additional responsibilities this Outer Circle attaches some set of responsibilities and this even Outer Circle attaches some other responsibilities and remember attaches additional responsibilities to an object dynamically and that's what we're talking about at run time or at compile time you can attach different responsibilities at runtime you don't have to set your mind to a particular set of responsibilities at compile time that's what they mean when they say dynamically next sentence decorators provide a flexible alternative to subclassing we actually specifically look at this because the example that they have of a situation where you might feel that you possibly need something like decorator pattern is a class explosion scenario where you have too many subclasses so you can think of it this way think about that classical saying inheritance is not for code reuse inheritance is not for sharing Behavior so it's a way of using composition rather than inheritance in order to share Behavior remember what we said before we we will use inheritance we will use Isa but only to to make this thing behave as if it was one of these things right we're not using inheritance to share Behavior we're using composition to share Behavior we'll get into this but we're going to use inheritance to make sure that this thing behaves as if it was this inner thing you can also think of it this way if you define subclass a subass b subass c then you only have ABC you can't somehow compose a new class at runtime that's a a a composition of a and b or B and C but with decorators that's actually what we're doing we're defining The Decorator a The Decorator B and The Decorator C and then you can actually compose you can use both decorator a and decorator B at the same time so it's more flexible but we'll get into this so decorators provide a flexible alternative to subclassing for extending functionality and that's what we were talking about so that's the definition in the book they use an example of a coffee house called Starbuzz coffee so essentially it's about constructing a menu of products that can be ordered at the coffee house so it's a bunch of different coffee types I guess so a customer comes in and asks for a particular type of coffee and they have tons and tons of variations of coffee so here's what they start with remember that now we're talking about a bad examples so this is not a suggestion of what you should do this is an illustration of something that's problematic so they have a class called beverage that has two methods get description I'll just try get desk in order to save myself the space but again remember to always use proper method names and variable names but just to Safe space so get desk for get description and it has another method called cost and this beverage class is an abstract class if you're not familiar with abstract classes abstract classes are essentially classes that cannot be instantiated so something has to inherit from beverage and then you can instantiate this thing but you can never instantiate this thing the reason for using an abstract class instead of an interface is that an interface cannot have an implementation right cannot put implementation details in for example the cost method but if you have an abstract class you can actually put a default implementation here in the cost method but you can't instantiate the beverage but however if you have so here if you have coffee for example then you could instantiate a coffee and if cost has an implementation here in the amstr class then coffee will get that implementation for the cost method that wouldn't be possible if you have an interface because then you would Define the existence of a method called cost but you would have to Define an implementation in the coffee class coffee class is responsible for implementing cost and it it can't inherit it from something so an abstract class is a way of defining a class that defines some baseline implementation or some default behavior that other classes can inherit but the abstract class is not instantiable you can't instantiate an instance of the abstract class moving on so that's the abstract class and then they have a few basic types of coffee so they have for example DCF and they have espresso and then they have a few more types but I mean in order to save space let's just not consider them but the other types that they have are House Blend and dark roast but you get the point you can have a multiple types of coffee that inherits from the the beverage abstract class and the method that we that they Define is cost because the Baseline cost of an espresso is different from the Baseline cost of a decaf coffee given the scenario that we're looking at right now right so when I talked about the abstract class before sharing Behavior I think I use the cost method as an example but what's what actually happens here is that get description that method has a default implementation that is not overwritten here or is not implemented here in espresso nor in decaf which means that the get description method is defined in this class and thus these subclasses will use this implementation however cost is probably not defined here or you could have a default implementation here but regardless it's possible to override here in decaf and here in espresso so decaf has some cost and espresso has some other cost which could potentially the same or potentially not but given the example probably not the same so the point here is that they have these sort of Base kinds of coffee but then the Crux is that they have a bunch of extras that you can get with your coffee or in your coffee which they in the book later call condiments but you can think of them as extras or as flavors or as toppings or as spicing so to be more specific these are things such as steamed milk whipped milk mocha soy milk etc etc etc and this is also the first point where I feel that their example is apologies but kind of stupid because who would ever then think that it's a reasonable idea to start to introduce a single class for each combination of these different things because the problem that they're pointing towards is of course that you could have both a mocha coffee with steamed milk but you could also have a mocha coffee with whipped milk or you could have a mocha coffee with soy milk or if you think about the flavor caramel then you can have a soy milk with caramel or whipped milk in Caramel etc etc etc just think about like if Define a few of these different flavors and then just imagine that any flavor could be combined with any other flavor because why not I mean people could come up with a strangest orders which makes sense if you're a coffee house right you want to actually serve the people who want you to mix different things just think about if you've ever been to Starbucks or espresso house or any of these places I mean of course you can get crazy combinations of the toppings or the extras that they have and if you introduce a single class for each combination right you have steamed milk caramel whipped milk caramel etc etc etc if the first one is a class the second one is a class the third one is a class each and all of these are different classes then you'll have what is commonly referred to as a class explosion you'll very quickly find yourself in a scenario where you have tons and tons of classes and they all do very very small things right so from single responsibility principle's point of view maybe that's a good thing because they do only a very small thing but it's completely unmanageable because you have so many of them and instead of me actually draw drawing this here let me just show you this picture and I I I think you'll understand what I'm saying so what serious class explosion so that's an example of a poor way of approaching this problem so then they suggest another poor way of approaching this problem that might also actually be intuitive to a lot of people especially when you're you're new to programming so the second suggestion that they have is to say that all of these different things like whipped milk soy milk caramel Etc could be treated as booleans could be treated as true or false false values so the concept of having steamed milk could be treated as a Boolean where if you put steamed milk into the coffee has steamed milk is true if you don't then it's false that's kind of simple right so you just enumerate all of the different things so which means that we need some more space here so we add decaf and espresso both having the cost method and both inheriting from beverage and then in beverage we put all of these boans so has milk has soy has caramel has whipped and so forth and so forth and so forth and actually whipped was probably whipped cream rather than whipped milk but whatever and actually because of the examples in the book are in Java they're not using Getters and Setters that you have in CP so these would correspond to Getters but they also in the book Define Setters so you don't only have hasm milk you also have set milk so you say set milk which sets milk to true or you say set milk in pass a Boolean so setting it to true or false but I mean that's irrelevant to this example of course you could also pass these through the Constructor for example right so you could have upon creation of a beverage you supply 1 2 3 four booleans so true for milk false for soy etc etc etc and I mean you can see that for one this is extremely unexpressive to pass all of those in and even setting these as parameters feels very odd I think Sandy mets has a great saying when she says that conditionals breed so if you have one conditional that would likely put you in a place where eventually you'll put even more conditionals in your program and I I can't remember who said this please put that in the comments if you remember but somebody said that returning booleans usually provokes conditionals elsewhere in your system so the fact that we're returning a Boolean will provoke the need to at some other place switch over that conditional in other words include that conditional in some kind of switch statement or if statement or something like this essentially in some kind of condition and the idea that you should stay away from conditionals is a topic for another discussion let me know when we can have that discussion but beyond these problems there are some other problems that they highlight in the head first book one of them is that you have to change existing source code when you want to add a new condiment or when you want to add a new extra a new flavor so if you want to introduce chocolate for example so maybe you want to put chocolate in your coffee then you have to actually change the contents of this class by introducing has chocolate question mark and this violates the open closed principle so that's why they're suggesting that's a bad idea but I think perhaps even a more severe problem that they're also highlighting is the fact that because these are inheriting from beverage they'll also inherit all of the methods here so perhaps you're already familiar with the interface segregation principle and Lisk of substitution principle these are two of the principles from the solid design principles of objectoriented programming and the interface segregation principle states that a subass should not be forced to depend on methods that it does not use so for example they actually have a very great example in this book the example is that what if you introduce tea and make tea inherit from beverage because it is a beverage and you want to be able to treat all of the beverages all of the menu items the same so you can print them to the menu but what if some of the methods that we've put here actually don't apply to tea so hypothetically I mean maybe these do I apologize these do but maybe chocolate simply doesn't apply to tea like it's so absurd that you can't order it you can't order tea with has chocolate then we're explicitly breaking the inter face segregation principle because we're forcing because T is inheriting from beverage and we're forcing T to actually have the default implementation the the implementation in the abstract class of has chocolate even though it doesn't want to use it so if you're interested in the interface segregation principle I've talked about that previously in other video so if you're interested I'll link that in the show notes check it out but shortly the problem is that if you just think of an example where you have an instance of the T class you could have an instance of a t class without knowing that it's a t class because you're treating Tre it as a beverage right that's the point of having inheritance so you have an instance of a of a t class you have an object that's of type T but you're treating it as a beverage and because you only know that it's a beverage you could call has chocolate but tea surely doesn't have chocolate and now in this particular scenario that's not necessarily too dangerous but on the general plane that's a crazy idea because this method simply doesn't apply to this class it's not that it's not doing anything it's just that it's it's like it's it's completely undefined it just doesn't make any sense within the context of T and that's why we should separate these so the interface agregation principle essentially says that it's better to have multiple smaller interfaces than one single large one which is exactly what we have here a single large interface another problem with this design that they rais in this book is that they say what if a customer wants now I didn't put mocha here but their example is what if the customer wants a double mocha a better example perhaps might be an espresso shot I mean most coffee houses have its own that you can get your coffee and then you can get a shot of espresso in your coffee in whatever coffee you had and then if you just think about the concept of one shot of espresso if you can have one of course you could have two and if you could have two then why not have three hypothetically right and that means that you would have has expresso shot but then you would also need to have has double espresso shot and then has Triple Espresso shot then you're also in a sticky situation where you have to say okay if I have a triple espresso shot I shouldn't also set has double espresso shot to tr that's kind of tricky to manage but also kind of stupid because the the second espresso shot is just another one of the same thing so why would that have to be a second one but of course then you could also think about strange designs such as saying that okay instead of making that a Boolean you would make that an integer and then you count the number of times that you have but I mean hopefully you're feeling that we're sort of treading down a slippery path where it's just going to get more complicated then you would have to calculate the cost I mean obviously maybe I didn't mention that before but the point of keeping track of all these things is that the cost varies based on what kind of condiments you're actually putting into your coffee so then the calculation of the cost method how to actually calculate the cost of this particular beverage becomes very complicated when you think about has espresso shot being an integer and has soy being a Boolean so you'd have to have some nasty Logic for the cost method where you would say okay if it has three four espresso shots then it's this price if it's two of Espresso shop then it's it's this price but then plus the fact that you have soy which makes it this so if has soy BL etc etc etc I mean hairy very hairy so not a good idea right what can we do and this is when The Decorator pattern comes in so let's start off by looking at The Decorator pattern applied to this particular example and then after that we'll look at sort of the generalized uml diagram and talk about the decorator pattern in general and again remember that I I'm not saying that decorator pattern is actually suitable for this example that they've chosen this illustrates the way you use decorator pattern very well but I don't actually think that this particular use case is is suitable for decorator pattern moving on let's check it out so we start off with the class beverage again the beverage has get description and it has price and it has cost so cost returns to the price of this particular beverage and get description returns some kind of string representation of the contents of this particular beverage again remember that it could get complicated because you can have all of these different condiments all of these different extras all of these different atoms and then we have those two basic types that we had before we have decaf and we have S espresso and both of these have their own implementation of the cost method because again they have different Baseline costs so the price of an espresso is different from the price of a decaf assuming you put either no other condiments or you put the same condiments in them now how do we make use of decorative pattern instead of introducing multiple classes that represent all of the different combinations of the condiments you have espresso with mocha espresso with caramel and so forth and so forth instead of that what we'll do is that we'll introduce a condiment decorator but because of the length of the word condent I'll just use the word add-on instead I'm meaning the same thing it's just to make this simple so it's an add-on to your sort of Baseline coffee so you have the Baseline coffee and then you add on something else such as whipped cream so we'll call this add-on so add-on decorator which implements the method get description but remember what we said in the beginning about decorator pattern the essence of The Decorator pattern is that The Decorator is a component and has a component so this Arrow denotes that it is a beverage but it also has a beverage so the add-on decorator is a beverage it behaves as if it were a beverage so you can call get description just like you can call get description here sorry I should use the same name because we mean the same method I use a short notation get desk you can call get desk on an add-on decorator because it is a beverage and you can call Cost even though we don't Define cost here because all beverages have costs and if the cost has a baseline implementation here then you have an implementation for cost and you can then you can call cost in the add-on decorator so then it behaves as if it were a beverage because it is a beverage but it also has a beverage we'll get into more about why this is and what this means but what we then do is that we say that the add-on decorator has a number of implementations a number of different classes are add-on decorators so I'll just do two but you have to realize that you could have as many as you want and that's the point that right we were talking about different condiments before different add-ons like soy and whipped cream and caramel and chocolate and so forth and so forth and so forth and all of these could be different add-on decorators or in the book condiment decorators so let's do one let's say caramel so caramel now if I would put this in COD I would probably actually call this caramel decorator just to make it very clear to the person that this is a decorator remember the power of using semantic naming of using proper naming so that other people can understand what you're actually doing but here to save space and as they've done in the book I'll just call this caramel and let's choose another one with soy and these that are decorators that are add-on decorators these Implement both get description and cost so both of them have get desk and they have cost and this might seem really odd and don't be frightened but it's actually kind of smart so the point here is that remember the original image that we drew where we have one class in the middle and then something that wrapped it and another thing that wrapped it here's the point the object in the middle right the instantiated object in the middle that's a beverage the thing here the thing that wraps it the first decorator is an add-on decorator it's an add-on decorator that is a beverage it behaves as if it were a beverage but it also has a beverage and that's what we're trying to denote when we're drawing it outside or like as if it were containing this inner object this beverage so this thing is an add-on decorator and this thing is actually an add-on decorator as well so we have an add-on decorator as in the type we have an add-on decorator that wraps another add-on decorator that wraps the beverage and concretely now we're talking about what sort of abstractions they are of but if we talk concretely this object has to be either given that these are the only classes that we have it has to be either an espresso instance an instance of the espresso class or it has to be an instance of the Decap class because this is a beverage and this decorator and this decorator has to be either a caramel decorator or it has to be a soy decorator one of them so this could be caramel and caramel or caramel and soy etc etc all of the different combinations that you can imagine so the point then is that with this design what we've constructed is that we've constructed a situation where instead of having a single class that describes decaf a single class that describes espresso a single class that describes decaf with caramel a single class that describes espresso with caramel a single class that describes decaf with caramel and soy a single class that describes espresso with caramel and soy and so forth and so forth instead of having all of those classes in the class explosion scenario instead of that what we've done is that we've separated the concerns like this and we decorate in all of the different animals that we want to add to the coffee so how do we do that we wrap them so with this design you can create an espresso with caramel you could create just an espresso you could create an espresso with caramel and soy by saying I'll create an instance of espresso then I'll pass that instance of es espresso to a caramel and then I'll pass that instance of a caramel decor at espresso to an instance of a soy class essentially making that a soy decorated caramel decorated espresso right and you can see the critique creeping up of the fact that this design pattern often makes it much more difficult to reason about your code and after you've wrapped it and wrapped it and wrapped it and wrapped it it's kind of tricky to remember what you actually have and as far as I understand if you're interested in order if you're interested in the order of how you wrap things and this design pattern is not suitable for that scenario scario but that's a different discussion so we haven't really talked about what get description and what cost what what these two methods do so let's quickly talk about that let's actually only talk about the cost method because I think you can figure out how get description Works in exactly the same way so the point is again that depending on which add-ons you put into your coffee the price will be different so remember that the idea of the cost method is that it returns a number that represents the cost so for the sake of Simplicity let's just say that it returns an INT so the cost methods here in the beverage classes these cost methods they in some sense return the Baseline cost so if you just order an espresso then this is what you'll get so say the price of an espresso is one and the price of a decaf is two hypothetically I mean never mind the currency and never mind the relative pricing let's just say that these are the prices and then let's say that when you add caramel to whichever beverage you already have you add an additional two to whatever cost you already have and let's say that when you add soy you add an additional one to whatever cost you have so if you get hypothetically if you get an espresso with caramel and soy then you should have 1 + 2 + 1 so 3 + 1 4 so the price of an espresso with caramel and soy should be 1 + 2 + 1 so 1 3 4 and in the same way for all of the different combinations so if you get a decaf that has a baseline cost of two and then you only add caramel then you add two and then you also end up with a price four and so forth and so forth I think you can see how that works but how do we actually Implement that what is the implementation of this method and why isn't it actually the same as this method because if you think about it you could just keep wrapping decorators and decorators and decorators why do you need to have something here that's different from the decorators if you're familiar with recursion you can think of it as that this is the base case so you're using recursion to go down the chain of decorators but then at some point you need to reach the base case which is this cost and this cost and then you can go back up but if you're not familiar with recursion never mind we'll have that discussion some other time you can just think of it this way this cost is an add-on this is not the Baseline cost this is a cost that can only exist if you have another cost that it adds to this cost is existent in and of itself this is the Baseline cost you can get this thing in and of itself you cannot get a decorator in it of itself caramel just by itself doesn't make any sense right imagine you go to the counter and you say can I just have some caramel and then you stick out your hands or you just I don't know drink it from the machine or whatever essentially that does doesn't make any sense within the scenario so decorators have to wrap something that can exist in and of itself so if you think about the implementation of cost here when we say that the cost here returns one we actually mean that explicitly the implementation of this method would probably be something like return one semic done that would be the implementation of the cost method and same thing you return to implementation of that method but the cost method here what that does is that it would say something like remember that the cost of it is two so it would say something like return this dot beverage do Cost Plus 2 so this do beverage we haven't talked about this but this do beverage refers to the fact that it has a beverage this thing wraps another thing and when when this thing says this. beverage it refers to this thing when this thing says this. beverage it refers to this thing when this outer thing says this the beverage it refers to this thing so from the outside it refers inwards so it refers to the thing it's wrapping The Decorator refers to the thing it's wrapping and in this case the thing it's wrapping happens to be another decorator but this thing when it refers to its beverage it happens to be an actual beverage so that's why we're saying get the cost of the thing I'm wrapping because my cost is is supposed to be added to that cost right we're saying plus here it's supposed to be added to this cost we take the Baseline cost which could be which is the Baseline cost if we're here right if we're here this the bage refers to this which is the Baseline cost but if we're here it refers to this cost plus this cost so essentially this stuff right and if we're here on the outside and we say this. beverage. cost we're referring to the cost of this stuff of the total price of the thing that you are wrapping because if you think about it this thing this outermost thing only knows that it's wrapping something and it's agnostic to what it's wrapping as long as it's of type beverage it wraps something that's of type beverage and it has no idea what the thing that it's wrapping actually also is a decorator that wraps a thing that wraps a thing that wraps a thing etc etc etc and then at some point down the chain you addend up with a beverage it has no idea it just knows that it wraps something that calls itself of type beverage and then it says okay give me the cost for your thing so it's like a black box right every decorator thinks that it's only wrapping a single thing but that single thing might also be a decorator that thinks that it's wrapping a single thing and that thing might be a decorator that thinks that it's wrapped in a single thing and so forth and so forth and so forth so when this when you want to compute when you ask this thing hey what's the cost it says actually for me to be able to report the cost I need to figure out what the cost is of the thing I'm wrapping and then add to that the cost that I have for myself if this thing is caramel then this thing should add two so it should say what's the cost of this thing that I'm wrapping and then let me add two to that because that's the cost of the caramel add-on and this is why it says this. beverage let me return the price of the thing that I have I am a decorator I have a beverage which might be a decorator or it might be a baseline beverage let me ask for the cost of that thing and then let me add whatever I want to that and get description behaves in exactly the same way essentially the difference is of course that that works with strings and this example it's a way of compulsing together a name that represents the whole beverage for example could say espresso colon caramel kaas soy or something like this right it's in some sense a way of iterating through this data structure it's a way of traversing this data structure which is by the way if you're familiar with that very similar to a link list it's a node that points to a node that points to a node Etc and returning and aggregating some kind of result so in the get description example we aggregate a string in the cost example we aggregate a number now let's look at the generalized uml diagram so the generalized uml diagram looks something like this you have a component in our previous case it was a beverage you have some set of me methods on this so we'll say method a method B you can't Define them here in the general case because it entirely depends on what you're actually building you have some method so let's call them A and B inheriting from the component is a concrete component which has method a and Method B inheriting because it is a component in our previous case we had an abstract class with a concrete class but it could of course be an interface and a class then also inheriting from this component is a decorator and The Decorator of course also needs needs to specify method a and Method B but again if it's an abstract class perhaps it only overwrites or defines some of the methods because some of them it may want to use from the component depends on your scenario but because it's decorator pattern that we're looking at The Decorator not only is a component it also has a component so The Decorator is a component but it also has another component so when you instantiate The Decorator you provide it a component so The Decorator behaves as a component but also has a reference to another concrete component and that component could be another decorator because a decorator is a component and that's on the abstract level so concretely we of course need to have concrete decorators so we have hypothetically concrete decorator a and concrete decorator B let me actually rename these from A and B to one and two just to emphasize that this A and B has nothing to do with the a& BS in the method name so these also have method a and Method B method a and Method B and concrete decorator 2 is a decorator and that's it that's the decorator pattern you instantiate a component you create an instance of a component it behaves as a component but it is a concrete component because this is an abstract class you can't instantiate the abstract class or if this is an interface you can't instantiate the interface so you instantiate the concrete component it's the concrete component and then then you wrap that you give that to some kind of decorator and of course again you can't instantiate an abstract decorator if this is an abstract class or if this is an interface so you have to instantiate either this concrete decorator or this other concrete decorator and then you when you instantiate that concrete decorator you pass it to component and that's how you're wrapping that in that concrete component so you're wrapping this concrete component within this concrete decorator so when you instantiate the concrete decorator you pass it to concrete component and then perhaps you instantiate another decorator perhaps the concrete decorator 2 so you instantiate the concrete decorator 2 and when you do that you pass it the instance of the concrete decorator 1 which was wrapping the concrete component and of course you wouldn't have to do that because that's the power of The Decorator Pann you could instantiate the concrete decorator to and pass it the concrete component so you would have something like that so maybe this is the concrete component and this is decorator one and this is decorator 2 and this is the concrete component and this is decorator 2 that's the flexibility of decorator pattern you can at runtime compose these in any way you want So before we look at some code in order to wrap this up let's just quickly go back to the definition from this book so the book said that the decorator pattern attaches additional responsibilities to an object dynamically so these are the additional responsibilities we're saying this defines some kind of additional responsibility and this defines some other kind of additional responsibility and when you have this object you can attach this additional responsibility dynamically to this object or you could attach this additional responsibility to this object but moving on further decorators provide a flexible alternative to subclassing for extending functionality so it's not just that you can take the the concrete decorator and and endow the concrete component with the power of the concrete decorator it's very very flexible because as we were saying before when we were talking about this you could take the concrete decorator 1 and also the concrete decorator 2 and endow the concrete component with both of them or you could take the concrete decorator one and create 10 instances of it and wrap them in each other and then the bottom wrap it around the concrete component so you have a concrete component that's endowed with 10 concrete decorator ones and in some scenarios in some applications that might make sense and some applications that might make no sense for example think of the cost method that we had before if the cost method were multiplying and if the cost of concrete decorator one was one then it wouldn't matter if you were wrapping multi one because if the decorators that you're wrapping all multiply by one then you would get the original price anyway because you'd say okay I have this base cost and then I multiply with one and then I multiply with one and then I multiply with one and then I multiply with one I multiply with one so in that scenario it makes no sense but The Decorator panel is completely agnostic to your scenario so syntactically programmatically you can do that you can wrap it just as many times as you want but in some scenarios it's just not meaningful but essentially I think this is how they're thinking when they're saying that it's a flexible alternative because it's actually very very flexible because you can compulse them in any way you like let's now super quickly look at a code example let's stick with the coffee example so we'll start with the abstract beverage class so we'll say abstract class Beverage open and I'll skip the description methods just to keep things short so remember that I'll only do the cost methods so because of that we only have public abstract cost the cost method remember that because it's an abstract class and we don't want to give cost and implementation here in the beverage class because we don't have a baseline cost for beverages we need to know which type of Beverage it is before we can give it a baseline cost we declare it as abstract because then we're saying that whoever subclasses beverage has to give an implementation of cost that's that for the abstract class and then let's do the add-ons in other words the decorators so then we have abstract class add-on decorator I'm running out of space here but continuing on the same line is of type beverage because remember Again The Decorator is a component so it is a beverage and the implementation of that is just that the abstract class is stating that if you are an add-on decorator then you have to give an implementation for cost because again there is no Baseline decorator this is only so that we can have the same type of all the decor Ator so that's why we're saying that they need a public abstract method called cost and again no implementation so in this particular scenario just to be a bit more complete of course we don't actually need the add-on decorator we could just say that all of the decorators behave as Beverages and have beverages moving on to the concrete implementations so a concrete beverage let's only look at espresso remember we had Decap and we had espresso but let's now only look at espresso so then we have a class called espresso which is of type beverage and has an implementation for the method cost right because it's a beverage it needs to implement the method cost so has a public I of course I forgot the type here I forgot the data type here so let's actually quickly add that public abstract int cost and public abstract and cost probably it makes sense to use a double or something like that but let's just keep it simple let's stick to ins so the espresso needs to have an implementation for public in cost it needs to have an implementation for the cost method and what do we return well I think before we said that the espresso has a price of one so because it's the Baseline implementation because it's the base case because it's the innermost thing because it's the the actual beverage then we actually just return whatever the price of that thing is so let's say we return one but what happens at The Decorator end so in The Decorator end uh let's do the caramel add-on so then we have a class called caramel and that is of type add-on decorator running out of space so the class caramel which remember is a decorator so in a real world scenario remember I I said before I would probably call this caramel decorator just to be explicit so that when people see the word caramel they know that it's not just a standalone class it's actually a decorator that needs to decorate something so the caramel decorator is a add-on decorator and the add-on decorator is a beverage so by proxy the caramel decorator is a beverage so back to that idea The Decorator is and has a component and now we've only described that it is a decorator but because the decorator is a beverage it by proxy is a component but then to the has part we say that a decorator has a component as well as is a component so how do we describe the has a component so we describe that by saying that it has of type beverage let's call it beverage and before instantiation we can't know what that is so for the Constructor public caramel so in the Constructor public caramel we take an argument which is of type beverage beverage let me just call it B so that we can differentiate between the beverage that's passed in through the Constructor and the beverage that exist as an instance variable so in then in the body of the Constructor of the caramel decorator we do what we say this do beverage in other words this instance variable beverage we say this. beverage and assign that the value B close the construction so what happens here we assign to the instance variable beverage here we say this do beverage in other words we assign to the instance variable beverage we sign it the value B and B is what was passed in here through the Constructor so we have a beverage here in the caramel decorator and after construction after we've instantiated the caramel class we will have set the value of that beverage to whatever was passed in through the Constructor so again the caramel decorator class CL has a beverage has a beverage that's set through the Constructor but also is a beverage because here by proxy it is because it is a decorator and The Decorator is a beverage and that was the Constructor but then now we have to also implement the cost method so then we say public in cost and what's the implementation of that remember we drew that before when we said that the difference between the cost method of a decorator and a component is that the component do stand alone so the component can actually return it it own cost whereas The Decorator cannot exist in isolation it has to decorate something it has to decorate either another decorator or it has to decorate a component so that means that when we ask a decorator for its cost it can't just stand alone report its cost it has to report its own cost in relation to the thing that it's decorating so that means as we drew before that we can't just say return some kind of cost here instead what we do is that we say return this Dot bever bage this again this instance variable beverage this do beverage. cost in other words calculate the cost of that plus the cost that's for this caramel decorator and I'm not sure if I remember correctly but let's just say that that cost is two for example could be something else right I can't remember that's the same as we had in the example before so in other words we take whatever the cost is of the beverage that were're passed in through the Constructor and we add to that to so when you have some kind of beverage and then you wrap that with the caramel decorator then when you ask the caramel decorator for cost the caramel decorator will ask the beverage that it's wrapping let's say that that's the espresso beverage It'll ask that for its cost so we have the call to cost here and we have the same call to cost here but inwards and then this espresso beverage will return one so one will go up here but then the caramel decorator will take that cost and add to that another two so here we get one and then we'll get another two here but of course it's two plus the one that we already have so we get three out here and that's essentially it the methods that we have in all of these places are completely dependent upon your scenario and the number of decorators and the number of components that you have are completely dependent on your scenario so when we looked at the generalized uml diagram we said decorator 1 and decorator 2 and we said concrete component but you can have any number of concrete components on and you could have any number of concrete decorators so that's sort of on the class level and on the method level you could have any number of methods so here we happen to talk about only cost and in the earlier versions of this example we also talked about description so the fact that all of these had descriptions but you could have any number of methods and in the generalized we said method a and Method B and I also want to add that when I said that the decorator cannot Calculate cost in it of itself I mean that's accurate but it's also dependent on this scenario so in this particular particular scenario that's true so when I say that the cost method here cannot be computed without also looking at the cost of the component that we have a reference to in other words without looking at the cost of the beverage that we have a reference to that's dependent on the scenario generally the cost method could of course calculate something without looking at what it decorates so now we're leaving the whole context of a coffee house so just generally if you have something that's decorated by something that's decorated by something that's decorated by something and then perhaps this decorator is something like a reset decorator so you make a method called to the outermost decorator for something and then that call is passed in and passed in and passed in and perhaps this decorator completely ignores what's down here it completely ignores what this decorator reports and thus by proxy completely ignores what the component what the inner component actually reports so decorators can be used for tons of different things and if you want to think of it in terms of math you could think of it as as this thing multiplying by zero for example example and if you would multiply by zero then it doesn't even need to look at what's inside it doesn't even need to further the chain of making calls downwards towards the component because it's not going to matter what's in here because it's still going to take let let's say that what's in here we call X we don't need to compute X because we're still going to multiply X by 0o when we get to this point so then we could just say return zero so again the implementation of the methods that you have are completely dependent on what you're actually trying to model the point here is that you can you can construct this kind of component that you decorate that you decorate that you decorate that you decorate and then in some sense recursively quotation marks construct the value that you want so you make a call to the thing in the outermost layer that makes a call to the thing it's decorating that makes a call to the thing it's decorating that makes a call to the thing it's decorating Etc and then the value propagates up all the way back out and then you have your value but how that processing of the value or construction of the value happens again it's completely dependent on your scenario because it depends on what your modeling it depends on what kind of value you're actually looking for so that's the decorator pattern before we wrap up I said before that I wanted to mention why I don't think that this particular example is actually suitable for The Decorator pattern so in my mind what we're doing here is unnecessarily complicated for the problem that we're facing a more suitable way of approaching this problem I find would be to have a beverage class and in the beverage class for example via the Constructor you can pass it a bunch of condiments or as we call them adults or extras or flavors and these are all of the same types you have flavors and then you have concrete flavors sharing the flavor interface or the flavor abstract class or or whichever way you want to design that but the point is that you take these flavors and then you pass them into the beverage when you construct the beverage in the Constructor you pass a list a ray list whatever a a collection of addons a collection of extras a collection of condiments to the beverage and then when you ask for the cost you simply aggregate you simply iterate over the collection of extras and produ a value when we talk about iterator pattern for example you'll see why that's actually a very useful strategy because you're separating two different concerns you're separating how to iterate over the collection how to aggregate a value based on the collection and the actual values of each of the items of the collection so the reason I'm stressing this is that when we're using this for decorator pattern we're actually mixing these two concerns we're putting the plus here in each of of the decorators and what I'm arguing here is that that's unsuitable because of the thing that we're building it's unlikely that we'll want to change the plus to something else it's unlikely that suddenly if you introduce I don't know you put chocolate in your coffee you want to double the price from before that's unlikely of course you could argue that multiplying could become relevant if you would look at things such as different sizes of Cups then it could actually be that the price is the same but double if you have a larger cup but again I think this is totally over engineering we would do much better with just a list and then iterating over each of the values in that list by asking all of the beverages in that list what's your cost what's your cost what's your cost what's your cost and then add that up to a single value so in other words then the beverages wouldn't have to both produce their own value and add that value to whatever was before I'm arguing we're mixing two concerns here that shouldn't be mixed and probably if I try to generalize here probably the problem lies in that the decorators are too much alike so we're looking at a scenario where it's unlikely for any decorator to be significantly different from another decorator if the implementation of the cost method is significantly different between decorators then I think you're looking at a scenario where it's actually potentially very useful to use decorator pattern but if what varies between these different decorators is a single property or multiple properties essentially if what varies is a property then you're probably forcing in a pattern where it's not suitable so the head first book actually has an example which which is actually much more appropriate which is from the Java API so if you're in Java you perhaps recognize the concept of an input stream so you have an input stream which could for example be a file input Stream So if you're streaming from a file you're reading the contents of a file from disk and then you can decorate that file input stream with for example a buffered input stream with for example a line number input stream etc etc I mean I'm not familiar with this API but just by reading these names I'm trying to guess what they're doing so the the buffered input stream would probably help you buffer in other words read in chunks so you take a buffer input stream and then you wrap that around an input stream and then perhaps you would take a line number input stream which I guess helps you to get the line numbers as your readings so for example you construct a line number input stream and wrap that around the buffered input stream that's wrapped around a file input Stream So to me that sounds a lot more sensible and I think for two reasons one because we're talking about streams so The Decorator has a name that resembles the thing we decorating The Decorator is named stream and the thing we're decorating is also named stream whereas if you think about what we've been doing we've been saying that condiments addons are beverages but obviously they're not and that's one of the reasons I think this is actually kind of a strange example because decorator pattern is probably more suitable when your decorators actually very much are what they're decorating but again the second point is probably a lot more important than that was that the differences between these different decorators is is so insignificant that decorator pattern is simply not probably sensible if the only variation is the actual cost and when we had more stuff the name of The Decorator in other words the name of the addon or the name of the condiment as in like is it whipped cream then those are sort of on the property level and not on the behavior level I think decorator pattern is probably more suitable when we're looking for Behavioral variation we're not looking for variations in that here we have a two and in the other one we have a three that's not a behavioral variation we're actually looking for variation in this plus that's when decorator pattern is more useful when in some of the decorators you want to use plus and in some of the decorators you want to use minus for example probably math isn't suitable either because order matters but just again think of the input stream example when behavior is significantly different between the different decorators the same method in the different decorators so a very small example of when I've actually use something that looks a bit like decorator pattern in actual production source code is when I'm trying to deprecate something but I don't want to deprecate it in all of the places at once so assume I have this object I I have this class and it's used in a bunch of different places and I want to stop using this particular class but for some reason I don't dare to change it at all places at once so I'll create a rapper I'll create a decorator that decorates this thing and somehow intercepts the operation here so for some of the methods that I may want to deprecate instead of making the call to the thing here I just ignore making that call and let the decorator return a value or I for example do make the call but then somehow augment the value so that means that I can use the decorated version in some places where I where I'm ready to change it and I can use a non-decorated version in other places so that just makes deprecation easier so last thing before we close this thing about decorator pattern I forgot to actually show how we would use this so how would we go about creating a caramel decorated espresso what we would do is that we would say new Carl and in the Constructor we pass a new espresso and then we can save this into some variables let's say beverage b equals pardon the double lines and then if we call B do cost where we end up first is that because it's on the outer level because it's a caramel class because it's a caramel decorated we end up here in the in the cost method so when we call Cost here we say Okay return this. beverage. cost in other words we can't do plus two first we first need to look at the beverage that I have as a decorator here the beverage that I'm decorating so we go into that beverage which happens to be an espressive which happens to be this class and we call the cost method here right the beverage. cost we call this cost method then that cost method happens to return one so here we'll get one and then we add two to that so we get in essence return 1 + 2 because we add two to it and then we're back here and then this line then essentially equates to three and of course if we had multiple decorators here when we said new caramel and we pass in new espresso we can just keep on passing other decorators or wrapping with without the red decorator so we would say new decorator one and then through that Constructor Pass New decorator 2 and through that one's Constructor Pass New decorator 3 and through that one's Constructor Pass New decorator 4 etc etc etc all the way down into the innermost Constructor where we will pass a component and then we hit the base case so that's the decorator pattern I hope that makes sense if not let me know and then we'll try again the link to the book is in the description tons of more good stuff in there this is a playlist we're walking through all of the patterns in this book so in order to not miss the next pattern if you're not already subscribed be sure to subscribe thanks for watching I'll see you in the next one