Composite Pattern – Design Patterns (ep 14)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back to this design patterns playlist today we are going to talk about the composite pattern and if you just briefly think about the word composite composite means to be made up of parts a composite object is an object made up of multiple objects it's an object that's made up of multiple parts and here I don't mean object as an object-oriented programming I just mean object in general the word composite has that kind of meaning generally and that's the reason this pattern is named composite pattern because the reason this pattern exists is that there are cases where you might want to treat composites of objects and individual objects uniformly or or transparently in other words from the perspective of the user from the perspective of the client from the perspective of the person using your code sometimes you don't necessarily want to care about whether you are dealing with a composite of objects or a single object and here I literally mean object as an object-oriented programming whether you are dealing with a collection of objects or you are dealing with a single object with a composite pattern we can actually achieve this by making composites of objects and single objects both implement the same interface or be part of the same inheritance hierarchy and thus make it possible for us to treat them uniformly or in other words when I say uniformly it means if I happen to have a composite or in other words if I happen to have a collection of objects that shouldn't matter matter I should be able to do the same things to that collection of objects as if I had a single object in some scenarios I mean this applies whenever you have a problem of that sort but when you have a problem of that sort it might be super helpful for you to actually be able to to treat them uniformly to be able to apply the same operation to run the same function on a single object or a collection of objects but let's start to think about an example think about family trees so what if let me just remove this first so if this is me and I have two parents I'd say these are my two parents but my two parents both have two parents so these are their two parents then we have a tree structure and if we think about this tree structure there are some particular properties or earth phenomena or things that we can can name or talk about in relation to this tree structure one is that I am the root right I am the root of this tree structure but also if you take dependencies downwards from any point from my point you have the whole tree right I encompass the whole tree whereas if you would take this particular node for example that doesn't encompass this whole tree and I guess that's a consequence of being the root but if you look at only this node it has let's say children so it's a bit funny because I flipped this because I flipped the order of this example often times we talk about parents and children when we draw trees and then we say that this node has two children but now since I'm using a family example the child is upwards so sorry about that potential confusion so let me instead say that this node references to other nodes let me do this also let me make this directional right because I haven't specified directions of the arrows so we are not sure who references who but just within this example let's talk about the notion of having a parent right so we're not modeling the two-way relationship we're modeling nodes that have parents so again I have one parent and another parent and the first parent has one parent than another parent and the second parent has a first parent and it's and a second parent and then we could go on like right like we could go on indefinitely clearly but back to this scenario if you think about this node if you would look at a subset of this tree like this right so let me do this dashed and I mean just think about this - square here if you only think about this portion then this node is the root this node is the root and it has it references to other nodes it has two sub nodes so in the context of composite pattern this is a composite so the root is a composite because it has it contains multiple nodes this node in other words one of my parents is also a composite because it contains multiple nodes downwards I only drew this just so that we could think about the fact that if you only think about it in in steps of one level right or or or in relation to one node you can think of it like this so from the perspective of this node from the perspective of me what we have is that we have one node that references two nodes but if you change your perspective and you think from the perspective of this node from the perspective of one of these nodes that happens to be somewhere in a hierarchy from this nodes perspective we have exactly the same scenario and we have one node that the reference is two nodes and if you take this node as your sort of point of departure or as your venture point for thinking or if you look at the tree from that nodes perspective then you have the same thing again then you also have one node referencing two nodes so in some sense and how we can actually just redraw this let's say that this this first triple corresponds to these first three to that view this and I've already drawn the blue one the blue one dashed corresponds to this so this one corresponds to this slice and then lastly this last triple corresponds to this triple but in the whole tree and this might seem a bit stupid but but the reason I'm saying this is that this puts us in the mindset of reflecting about the notion of recursion I don't want to talk in depth about recursion if if you are not familiar with recursion from before if you would like me to talk about recursion in a specific video do shoot something in the comments we can dig into that but recursion is essentially self reflection or is essentially a method calling itself but in object-oriented programming an object of a type calling another object of the same type who calls another object of the same type which essentially means that you execute the same function but on different instances so it's the same function defined in a class but in different instances but again let's not think about recursion in general unless you want to but then paying something in the comments this wagon if we look at these slices we have these sort of cuts of three but if we think about it in a different way let's think about every node at a time right so if you think about this node this node is a composite node because it references two nodes this node is also a composite node because it references two nodes further this is also a composite node because it two references to nodes however these four nodes at the bottom these are not composite nodes these are simply nodes or whatever you want to call them within the context of your composite pattern and ending tree structures we tend to call them leaves so if you think about a tree right you have a tree which has a stem and then a bunch of branches and at the end of the branches there are leaves so at the end here that's a leaf that's a leaf that's a leaf that's a leaf and that's a leaf like the end of the branch like branches that don't have sub branches so these are all leaves and essentially at the point with composite pattern is that sometimes you may want to be able to perform some computation and you don't want to have to think about whether you are in a leaf or whether you are dealing with a composite so whether you are dealing with someone who has sub nodes or simply someone who is a node let me remove this stuff on the side here so what might one ask oneself but think about it this way let's go back to the the example of this being me and these are my parents and these are my grandparents so what if for example we wanted to write an algorithm that collects last names within this family hierarchy so hypothetically right we could say I have one last name my father has one last name and my mother has another last name and then my father's father have one last name but my father's mother have another last name and so forth so let's just assume that I have the last name a my father B my mother see my grandfather on my father's side D and then f G just some random names the point is then that we can traverse this tree and collect the names so if I have in my program if I have a reference to myself I can say I can ask my I can ask the composite I can ask the composite to say get last names for example and what the composite would do is that it would extract the name that it has itself and then it would say but actually because I'm a composite I cannot just report my own last name I need to ask the reference I have to this object for its last name and I need to ask the reference I have to this object for its last name so I as a composite need to ask the objects that I'm composing I need to ask them for their last names but because they too are composites they will ask their children or or their sub components or the objects that they are composing for their last names and this is the recursion so when the program asks me for last name say get last name what happens is that because I'm a composite the method would report my name but it will also merge that with or or concatenate that with let's say where we're constructing a comma delimited string or whatever so it will take my name but it will also concatenated with whatever this node reports as it left its last name and whatever this node the reports as if its last name but again since these are composite nodes they will report their last names but also the last names of their children or their sub nodes downwards sorry now I use the same colors for these arrows so it turned out quite messy but right but I think you see the point right the point of composite pattern is that when you have a hierarchical structure or let me put it this way you have some data that you can usefully model as a hierarchy then performing computation over that hierarchy becomes trivial because you can treat leaf nodes and nodes uniformly which means that you don't have to write if statements to say I am a leaf or if the length of my children or sorry in this case the length of my parents right the length of my sub nodes if I have no sub nodes then do this else do that in some sense in some sense that's the only piece of logic that we're trying to get rid of right we are trying to if you think about refactoring replace or conditional with polymorphism so instead of saying that we have a branch where in one case you do this and in one case you do that we simply use polymorphism to specify that there are two types maybe this I didn't say clearly enough before but I mark these these three nodes a sort of solid because they are one type and let's mark these in red instead so these leaf nodes are of a different type so the implementation for get last name will be one thing so there will be one implementation for these nodes and there will be another implementation for these nodes so composite nodes have one implementation and leaf nodes have another implementation and now that we're saying replace conditionals with polymorphism the point is that by doing that and then making them both inherit from the same superclass or implement the same interface or be part of the same inheritance hierarchy right be of the same type be able to be treated uniformly since they are able to be treated as the same thing we can put them in a data structure and then simply traverse that data structure and ask the nodes to run the method get' last name and we don't ever have to think about whether any particular component happens to be a composite or happens to be a leaf or happens to be a leaf and thus we eliminate that if statement but I've been talking for way too long without actually giving a definition for the composite pattern so let's look at the definition so I want to read you the definition from this book design patterns elements of reusable object-oriented software it's written by Gang of Four and this is like the classic design patterns book that sort of tried to put names on things that I assume other people who are also doing and by the way I highly recommend that you get this book or this book had first design patterns so this book had first design patterns I would say it's better if you want something very pedagogical it has more images more fun examples and all of that stuff but if you want something that's more like a reference book get this Gang of Four design patterns book and when in doubt just get both super good books even if I cover a lot of stuff in these design pattern videos there's a lot of stuff left to be discussed and this stuff you can find in these books links are in the description let's move on now to the definition the composite pattern composes objects into tree structures to represent part-whole hierarchies composite let's clients treat individual objects and compositions of objects uniformly this is kind of what we were saying right so composite pattern composes objects into tree structures and this is what we looked at here right anything that is suitable to model as a tree structure is a potential candidate for a composite pattern and we do this to represent part whole hierarchies and honestly I'm super confused by this wording part whole apparently this is my guess an idiom yeah I guess this is a common saying and maybe it's supernatural to some people I just find it's really confusing so like a just googling it seems the point is that any object is a part of the whole and the whole is a collection of parts and I guess this is what were they were trying to suggest by saying part all hierarchies anyways I mean you know you understand what a hierarchy is anything that can be modelled hierarchically next sentence composite let's clients treat individual objects and compositions of objects uniformly and this is exactly what we talked about it's like if you think about a hierarchy the leaves are single objects but anything before the leaves or collections of objects and clearly let me just mention this before I forget it here we looked at I guess binary tree right because this node has two sub nodes and this know it has two sub nodes and so forth so all nodes have two sub nodes but of course with composite pattern it could be that this node has 20 sub nodes right and one of these nodes have two sub nodes and another one has ten and so forth I mean two made sense in this scenario because I was modeling parents but but the composite pattern makes no restrictions on what it means to have a composition of objects if you have a composition of objects it might mean that you have 10 or 2 or 200 objects the point is that it's a composition of objects and it's not a single object and you could also of course have a composition of a single object I mean semantically this is a bit interesting but but clearly you since I mean just think about a list you can have a list of one element so I mean that's a composition with one element in it but the point is again that collections and individual objects compositions of objects and objects are able to be treated uniformly and asked the definition so I think on a general level this is sort of pretty straightforward and at some point if you haven't felt this already you will probably feel a bit angry because you maybe you're thinking well this sounds 100% like the decorator pattern I'm going to touch a slight bit on why and how composite pattern is different from decorator pattern but it will make a separate video on composite pattern versus decorator pattern versus chain of responsibility pattern but because I haven't made a video on the chain of responsibility pattern yet that a video video will have to wait but again this wire will touch only briefly on it now anyways so again I think on high level this is sort of straightforward but now we need to get into the details let's first look at the UML diagram then let's translate that into an example which I think makes a bit more real-world sense we'll talk about a to-do list manager if you're building an application that manages to do's and then finally let's look at some cold let's get started let me start by removing this stuff so here's the deal you've got something called a component and this component has some kind of operation it has some function that does something and this is the function that you want to be uniform across composites of objects and individual objects so hypothetically we call this operation I can't but I'm not specifying a return type because I mean generally we don't know what this operation does in your particular scenario so this is the interface that we will use to refer uniformly to collections and to individual objects which means that we will have two other classes that implement this interface or inherit from this class or after class if it's a class or object class but in this case I think the both two books that I mentioned model this as an abstract class but we will model this as an interface I will show you and tell you why in just a moment and then these two subclasses or rather these two classes that implement the interface we call leave which again is the the single object and not the composition of objects so the leaf nodes and not the branches Ellen the other class is a composite so just think about the terminology here component is the all-encompassing concept everything is a component a leaf is a component and a composite is a component however the implementation of the function operation may be different in leaf than from composite so let's now specify that leaf has the operation operation and then of course the composite has the operation operation now usually I don't diverge from what's in these books or the common literature generally this quickly so I apologize for doing that but here's the thing in this book and also in the head first book they add methods along these lines they say that the component has an ADD method a remove method at a get child and method so the add method if you think about what we're modeling we're saying that a component is either a leaf or is a composite by the way this notation is just because we have two things I mean it's equivalent to to drawing to inheritance or interface implementation errors right like this is just shorthand so a leaf is a component and a composite is a component ah sir before we go any further I was missing manera the composite clearly has components and this is the recursion portion sorry I was going too quickly by the way this funky arrow in UML with like the diamond here at the start is essentially the same as Association essentially the same as has ah so both this and this we know has a relationships so if we put a in one and then be and the other end so the first one is a has a relationship for s half B's and the second one is also has a relationship for A's have B's the first one we call Association and the second one we call aggregation in UML you know honesty I find this a little bit vague and kind of completely unnecessary because we don't necessarily have to use this we could just say that it's an association and then be done with it so because here we can specify even explicitly if we want to I mean a composite has a component yes but it can actually also have multiple components so depending on what we're modeling we could even say you can have zero too many components so a composition is a composition of objects the question is do you mean of at least a single object or do you mean of at least two objects but here we're actually saying a composite is a composition of anything from zero to many objects which kind of maybe doesn't make a whole lot of sense because if we say zero here and it's essentially a leaf right so I mean it's a bit shady but this kind of also shows you that which is the super tangental point but but it also kind of shows you how it's powerful to to write algorithms that work on collections of things rather than on individual things so if you think about the library jQuery for example I guess hardly even used anymore but they treated so when you retrieve Dom elements when you retrieved instances of things from a web page so if you searched for something and you only have a single match you still got the list of a single match right and if you got no matches you still got the list of no matches or an empty list essentially and if you had multiple matches you got a list of multiple things and then you could apply your algorithm to to that list so you always had to write the algorithm for a list of things so that's very powerful but it's also completely not related to what we're talking about sorry about that so back to this point let me also remove this has a back here where essentially then saying that composites can have components so what are we saying then I mean we are again building up the data types that we need to construct the trees that we drew before so everything is a component right but if you're drawing if we draw just a random tree like this then this is a leaf and this is a leaf but everything else is a composite so this is a composite and this is a composite but all of them are components so this is a component this is a component this is a component and this is a component but this but that's on the general level on the abstract level so that means that if we happen to have an instance of any of these things then when we call the method operation when we call the method with the function operation which implementation of the operation method will perform depends on whether we have a green or a red note here depends on whether we have a leaf or composite polymorphism right so actually I mean in this case I said that these are necessarily these two green ones are necessarily leaves they aren't necessarily leaves if we had modern bit so that composites could have zero components so let me just change that to two two athletes at least one right so composites have at least one component but can have multiple components because I mean yeah otherwise it doesn't really make any sense let me also say that we're not going to enforce that in cold here in these examples but but you could if you would want to anyways back to the point that I raised in regards to this book I said that they also want to add and add the method and a remove method the point with that being that let's say that in your program you have a reference to this object let's call this all right like in your program you have a reference to all and this is of type composite yes it is a component but we can see here that it has a sub component it has a it has a child component which is this component and because it is a composite the idea is then that what we could extend this tree if it's a composite then it happens to have one leaf at the current time I mean in the future we could add another another leaf just add another one actually I mean we could of course add another composite that in turn will have another composite and another composite that in turn maybe have leaves so the point is that as long as you have a composite in your hierarchy you could hypothetically keep adding further composites or leaves and build out the tree structure and the reason and that they add the add and remove methods is that they want to allow you to mutate to change this tree as you have it in memory the reason I'm not bringing that up here is that I think this is a sensible time to talk about mutation so be aware that this is kind of subjective and opinionated but as far as I understand it seems that we're sort of collectively agreeing that mutation should whenever possible be avoided and mutation means to change we won't dig into that in super detail but just think about it this way can you change the contents of something without making it a new thing so if you have a string and you alter that string does that create a new string or does it actually alter the original string so if you have let me put it this way if you have an integer called a and you put five into it and then you say a plus plus does that mean that a now is 6 or does that mean that you've created the number 6 here but you haven't assigned it to anything so it just disappears the difference being let me show you what if we do this if you had int a equals 5 and then you have int B equals a plus plus I mean I'm using making use of the plus plus notation because plus plus presumably then mutates the value so in the second case now B should definitely be equal to 6 but the question is whether a is equal to 6 because if a is equal to 6 you've suddenly changed the value of something and again I don't want to dig down into this but I mean without making it complicated the point is if I have a data structure is it possible to change the data structure or if I want to change the data structure do I have to create a new data structure that is similar to the old data structure but now but has the new change and again I think we're sort of collectively agreeing that whenever possible we should use immutability we should avoid the mutation we should avoid allowing things to change and this is one of these scenarios like building hierarchies I think it's completely unnecessary to build hierarchies that are immutable unless of course I mean you could argue that it's very very suitable for your scenario but even then I would guess that it's a pragmatic solution I mean I would assume that there are immutable solutions for almost every mutable solution so however you know if like some specific scenarios really require it unless of course mutation is an inherent part of the requirement of the application but anyways so this is sort of the reason that I'm skipping the ad and the remove methods but now you know kind of what the intent of those were and if you want to know more about that you can check out these books for some information if you have the headfirst book I'd caution you that for this particular chapter I don't think there nuancing this discussion enough so maybe read that with the great salt if you have the Gang of Four design patterns book I think they do a little bit of a better job of nuancing that discussion but again I think there's there's more that could be said let me make this super explicit why it's also kind of becomes a problem because when they add the method and here and the method removed they add it to the base class and then they focus their discussion around whether these two methods should be in the component or whether they should be in the composite because if they are in the composite suddenly we've lost this transparency we've lost this uniformity where Leafs can be treated exactly as composites because then we can't just pick out any node when we're traversing this tree and say add on it because if it's the leaf it doesn't have the add method we can't make the program compile if we're in a compiled language so then we would have to typecast them and we would introspect we would check the type and see if it's a composite type cast it to a composite and then call the method add or remove because then we know that it exists if you've seen my other videos on typecasting you know that I'm just fundamentally opposed to it so that's not even an option at least for something like this I mean if you have some esoteric scenario for sure but but this seems too trivial to have to force us into a position of typecasting so the other alternative is to put add and remove here in the component but the problem with that is the interface segregation principle which states that clients implementers of an interface should not be forced to depend on methods that they do not use literally literally this is what the interface aggression principle states clients should not be forced to depend on methods that they do not use and that's exactly 100 percent whatever it was and exactly what happens here we're saying leaves need to have the methods add and remove because we want to be able to treat them as components but it fundamentally makes no sense for a leaf to have an add and remove method unless a leaf can actually add and actually remove so they go through all these hoops of like okay should we throw an exception here or should we return no or should we silently doing nothing and I mean okay these are all semantics so it might be that you're in a case where one of these cases is valid might be right and then that's super fine then it's not actually a violation of the interface segregation principle remember that all these things are semantics right like it's difficult to say whether something is objectively incorrect you have to argue for your particular case but this just seems to me like we would never find the solution for a good case however if we would look at immutability what we could do is that if we said that these hierarchies that we're building up using the composite pattern or immutable meaning whenever you've built the hierarchy you cannot change this hierarchy you've built it that's it what you can do is you can create a new hierarchy that looks like the old hierarchy but it's slightly different and that's the way of changing it and this is I mean if you are if you are familiar with JavaScript frameworks like react for example that's kind of the way that works so I'm saying that also to emphasize that this is not sort of some esoteric academic idea it's it actually like it's highly useful and again that I maybe wasn't clear about before but because programs with a high level of mutability are difficult to reason about so when things start to change underneath you and especially if you're doing a synchronous programming it's very difficult to reason about what state things currently are in but if you can make the assumption that things always are in the state that they were when they were originally instantiated it's much easier to reason about and again it's not super difficult to implement things such as copying the whole tree and then making that particular change we won't talk about that now but do ping if you want to talk about that and maybe we can talk about that in a future video anyways so that's why I was saying that if we instead construct these types such that we can build immutable hierarchies then add and remove can suddenly be part of the component because they suddenly now make sense in the leaf because the leaf if you call add on the leaf what it could do is that if you are here right this is a leaf if you call add on that leaf and pass it another leaf what it could do is that it could return you a new construction of this relationship it could return you a composite that has a relationship with a leaf so a composite object here and the leaf here and clearly maybe this node here that we were copying maybe this contained eggs and now this composite contain because again you can't add in the old scenario you can't add to a leaf because leaves can't have children so you need to transform the leaf into a composite and then add but when we were doing it in an immutable fashion you can return the new value for this subset and then you can simply reconstruct so you can take out the value from this old leaf put it into a composite and then add a new leaf to that composite but I mean I'm sorry this is total overkill for this pattern if this doesn't make sense to you don't worry about it ping me if you think this sounds interesting and we can talk about it some other time and generally whenever you can make something immutable make it immutable whenever you can avoid having a data structure that changes that changes its state avoid allowing it to change its state so this is why we are not talking about the ad and the remove methods but again if you really want to read more about that check out the books anyways ok let me remove some of this stuff from the sides let's now move into the example so the example I want to give is related to user interfaces if you've read anything about the pattern before you've probably come across some user interface related example and actually I think these are as relevant today as they were in for example the 90s but but today we find these examples in frameworks such as for example and react so we're not going to talk about specific frameworks but if you are familiar with anything like ember j/s or angularjs or react maybe even view jeaious I don't actually know because I haven't tried view but it might be might not be but either way the point is that frameworks that are a component based that are built around the notion that a view is built from a main component that can be these structured or or decomposed into smaller sub components and every smaller sub component can be structured into smaller sub components so the big huge main component has maybe two sub components and each of these sub components have multiple other sub components and that's the way you structure a page usefully because then you can for example say refresh to the outermost component and then that refresh command can trickle down into all of the small pieces of all of the components and that's not the way it's used in for example Redux but I mean I'm not a heavy Redux user but I mean but that library and other frameworks I guess or reviews the approach that you should send the data downwards and then propagate events up so that for example if you have this massive state tree that describes the state of your application you give it to the main component and then sub portions of the state tree sub portions of the information that should that should currently be displayed in the application is sliced off and passed down into sub components so that every component gets its its tiny piece of the state tree that it needs in order to display whatever it needs to display but those are some real-world examples and real-world analogies but anyway let's talk about a simpler example so imagine imagine that you are building a to-do application and his to-do application is super simple you just have let me draw some to do tanks and then you have a checkbox next to it then you can check as to indicate whether it's done or not and then a to do list is simply a collection of these two do's well I should say a list more specifically lists of these two do's where they can be checked or not but then this is that we get into composite pattern then we say what if you can have sub tasks of tasks what if you can have sub to do's of to do's so maybe this to do is comprised of these two do's and then we have another main to do out here and then clearly of course we could go further down into this hierarchy indefinitely so this to-do has three sub - dues this to-do has one sub to do and this sub to do has another sub to do and again then if you think about this it's the same thing as saying that okay you have a bunch of to do's and each of these two do's can either just be a to do or they can have sub to news and so forth so it's so it's a tree in some sense and the reason we want to use composite pattern here is that we have the following requirement what we want to do is that we want to be able to generate HTML for this so let's say that we have objects in a memory and describe this but we want to be able to operation essentially the function that we want to run is that we want to say give me the HTML that represents this to-do list and we're just going to do it super simply I mean hopefully you're familiar with this this level of HTML but let's just say that we use Li elements to represent these so it's an Li element with some text that's the to do right and then maybe this is a check box but maybe we'll skip it just to make it simpler and then clearly when you have Li elements you need to put them inside of a UL right that's that's how lists work in HTML which also then means that when we have a to do that has some to do's we need to have a new UL so actually let me remove this stuff because it's getting a bit cramped actually before I remove this I want to get into the the UL stuff but let me just let's let's establish some terms for our example here instead of these sort of generic names so in this diagram we had the component the leaf and the composite and in our case what will we have well let's say that this is maybe a to-do collection let's say okay let's say to-do list we have a to-do list that's sort of the the main type it's called a to-do list and then what do we call a leaf well we should call that maybe your to-do and then and then I realized the naming got a bit tricky because I mean if this is a to-do list what will this be I mean previously we had component and composite so I mean I think yes maybe this would be to do soar to do collection or parent to do and we could call it multi do actually let's think of it this way let's call this a project so that actually makes a bit of sense right like if you have a to-do that has multiple sum to dues but it still has a name and it can be completed or uncompleted then maybe that's a project so a project is in some sense a to-do list and a to-do list is comprised of either a project and a to-do list is either a project or order to do I mean it sounds kind of funny in this sense but hopefully I think actually this will play out quite nice but let's see so anyways I was about to delete that do we want to do that no actually let me use this space here so what I wanted to do is just super quickly say something about how lists in HTML work just so that everyone's on the same page I mean so if we want to have an unordered list in HTML we say ul and then we put Li elements that will contain all of the items and then we close the UL element whenever we are done but let me put these items first so just say 1 2 3 sit and then we close all of the individual li elements and by the way Li stands for a list item so you l stands for unordered list and Li stands for list item this is an unordered list of three list items and we need to close the unordered list but what I want to do is also show that the fourth element here let's say that we have a fourth element here we could also say that this one also contains a ul which in its turn contains a bunch of Li elements so and here we close this ul we close this Li and we close the outermost ul we need to close these as well so let's say fourth one and fourth - and then we close these sub Li elements so hTML is necessarily a bit messy right but just think about which tag closes this tag this ul closes this ul these allies are all closed on one row but then this Li is closed here and this ul is closed here and then these allies are closed individually so whenever you have a list of items we need to have each item and wrapped in allies but that collection or that list of Li items need to be wrapped inside a set of UL tags and then whenever we have sub lists whenever we have projects using our terminology we need to introduce another ul within an li but we also use the name here which is then supposed to be the name of that project so if you think about this if you look at only let's say this subset here then this is the name of the project and these are the sub - dues of that project meaning that this is a composite where this is actually the composite and these are the leaves that the composite is pointing to that these are the children of that of that composite and again if you think about the first example we took it way back in the beginning I use children in the opposite sense because then much it was maybe a bit confusing but again when I say children here now I mean what's in the collection of that composite the composite is a collection of object the composite is a composite of objects and this composite is a composite of these children of these objects so again if you think about only that subset then that subset corresponds let me choose a different color is let's see equivalent to is subset here so that looks a bit counterintuitive because I'm including the texts I'm including the text but not the Li element and then I am including that the sub list the whole UL element and the reason for this is I gave this a bit of thought just in my head before I started making this video and I thought actually there are two interesting paths that you can take when when modeling this either you say that a composite element includes an li tag or it simply includes only the text or if you think about it from another perspective the leaf that makes more sense if you think about the leaf does the leaf include the Li tags so you have the Li tags and then you have an item item text where I should actually say text here and then you close the li so either this whole thing is a leaf or only this thing is a leaf and what I decided is that if you would have the check mark I would put the check mark inside here so the text and the check mark are not a check mark sorry the check box the check box and the text I would say is part of the leaf but the Li needs to be part of a component hopefully this will play out when we when we think a bit more about the scenario movie when we look at the code so the reason I'm raising that question is that what code you put in in leaves versus what code you put in components depends on your scenario but it's also possible that you have multiple solutions for your scenario but with different benefits and with the different drawbacks so one drawback of doing this for example like making the allies included in the leaf is that since leaves are to-do lists it would then be possible for the user of the code to say that what I have is not a tree what I have is simply a single leaf and then that single leaf would render as an li element without wrapping UL element and that's sort of the the killing blow for me that's when I thought okay wait in this scenario I think that's an unacceptable drawback so I would think that you definitely always need a ul but at least if you put only a single to do we can't run their only li elements because that's probably not even valid HTML instead let's only then render the check the check box and the text maybe that would make sense right like maybe you could reuse that component in a different but anyways now we're getting ahead of ourselves the general point is that in composite pattern you can think a lot about what should be part of the leaf and what should be part of the component anyways this is what I decided so this means we drew this red area here to specify that this is part of a composite let's draw the same thing for a leaf so as I drew down here then the leaf would then simply be this thing the text and again if we had a checkbox it would also include the checkbox so these are all leaves and actually here these are leaves as well these are leaves fourth is not a leaf because it's composite and if you think about the whole structure this whole structure is actually a composite as well which probably means that it needs to have some kind of title here if this is the structure of our composite so maybe we will call this our to-do list so hopefully you can start to see now how this pattern could be useful in contexts where you have sort of a data that's hierarchical by nature such as for example HTML I mean in some sense then it's kind of trivial to construct your your object hierarchy and then render HTML from that object hierarchy so this operation here in the to do essentially only has to specify how to render this which is sent essentially just to return the string that represents the text that is contained within this to do and then the project in this case or in the general sense the composite simply has to has to figure out or the algorithm that we have to write simply has to be how to render this stuff which is essentially just a string comprised of the title concatenated with an opening ul element and then we iterate through all of our children we iterate all through all of the components that we have that's that's part of this composite and then we call the operation on them sorry I didn't change the name of the operation here perhaps the name of the operation here in order to do example should be to HTML or something along those lines right I'm saying to HTML rather than render because I'm trying to imply that it would return a string rather than sort of print at the screen or whatever but then this to HTML method of the project essentially of the composite but then I have to figure out how to print that so again as a how to render this area depends on the number of components that it has so it has a list of sub components and it iterates through this list subcomponents and puts an Li an opening Li tag and then calls get HTML or two HTML for that sub component and then whenever it has that HTML closes the Li tag next step of the iteration prints and Li tag again or ads and Li elements to the string then calls to HTML on that next child of the iteration on that next sub component gets this text back and then closes again so here's where the recursion gets in but I think it's probably easiest now if we start to look at the code but just think about this example just remember that this is sort of where we are going but let's let's now try to model exactly this scenario in some sort of pseudocode let me remove this stuff okay so let's define the stuff that we have let's start with we have an interface that's called to-do list open that up then we have a class that's called to do and that's the leaf and then we have a class that's called project which is a composite of - duze project and immediately I forgot that - duze should implement the interface to do lists and projects should implement the interface to do lists okay to do lists to do and project so the to do list interface simply specifies a single thing it specifies that in order to be a to-do list you need to have a method that returns a string and it needs to be called get HTML and that's it for the interface and actually this division is pretty stupid because if that's it for the interface there's no need to allocate all the space to that so let me remove this divider and let's just draw it here instead yeah sorry so let's just redo this so we have the interface to-do list and then we have two classes we have project that implements the interface to-do list and we have to do that implements the interface to-do list and on the general plane this to do is the leaf and the project is the composite and of course the to-do list is the component let me extend this divider now what about implementations so the to-do needs to maintain a property which is a string and it's called it text so that text is the text of the to do I mean it's the actual to do like by milk so then in the constructor of the to do let's say public to do we accept what we accept a string which is the text we open up the constructor and then in the constructor we assign this passed in text to this property text of the instance to doer of this instance variable text so we say this dot text equals the text that we were passed in and that's it for the constructor then the crucial part we need to implement or we need to supply an implementation for then get HTML method so we have a public method that returns a string and it's called get HTML now it doesn't take any arguments but what's the implementation well according to what we talked about before what we specified what we said is that it should not have to return Li and then the tanks and then Li it should not have to return these elements instead it should only return text simply and then you can imagine that what we would also do is that we would add a checkbox so instead of added just the text we would probably have like I can't remember what the syntax is in HTML but it's probably something like like an input tag where the type is equal to a check box and maybe that's self closing or I can't remember and that we put the text so but I'll skip the the check box and you can just imagine that whenever we say text we mean that maybe we should probably have a checkbox in front of that but if the job of the get HTML method is simply to return the text for the leaf then that's super simple then we just say return this doll text that's it then we close this we close the get HTML method and then we close the class and then we're done with it to do class that's it for the leaf now to the more trickier part let's talk about the project let's talk about the composite to do so in other words to do that has sub - duze it - needs to have not a text but a title right a project has a title so it has a string and let's call it title but because it's composite it also needs another thing what it means is that it needs some kind of ordered collection in our case ordered because we care about order ordered collection of components in other words of to-do lists which by extension that means that it needs a collection of either - dues or of projects because both of those can behave as as component or as to-do lists so let's just say I'll use sort of c-sharp like syntax so we'll just say we have a list of to-do list and let's call it - dues but then on to the constructor so let's say public project and it will take what arguments so firstly clearly it needs to take let me do let me do a line break here sorry about that it needs to take a string that will represent the title right which is the title that we will set to this instance variable clearly but now is where we get the repercussions of what we were talking about before about immutability if we don't want to be able to add in components or rather to-do lists after we've created this project but rather we want them to be added from the start that means we need to accept this list of to-do lists in the constructor so upon construction of a project you need to supply it with all of the to-do lists that it will contain so we do this because then we can avoid exposing methods that you can use to mutate the contents of this list which means that it sort of behaves as an immutable data structure which in again in my opinion is good but clearly can be discussed so anyways that means that we have a second argument not just the title but we also need to take an argument which is a list that will contain to-do lists and let's call it - duze close the parentheses open up the constructor and then what we do in this constructor is simply that we say okay this dot title equals the title I was passed in and then this dot - duze equals the two dues that I was passed in and then we close the constructor and I mean in essence we're doing the same thing here as we're doing here we're just assigning the values that were passed in through the constructor to the instance variables so were passed a title and were passed a list of - duze and we're taking this title and we're taking this list of - dues and we're signing into the instance variable title and - duze they stop title and they start to do so that we can have access to it across this instance now that's the easy portion of the project the more difficult portion of the project is now that we need to implement this get HTML method so let's let's let's start so we need to have a public method that returns a string and is called get HTML takes arguments and let's open it up so what will this implementation do Oh what we said that it will do is that it it's responsible for printing the UL and then printing the HTML of every item every every to-do list that it has in its list of to dues but wrapping all of those within allies because remember the to do's didn't print their own allies so the project must be responsible for printing not just the UL but also the Li so how do we do this there are clearly more elegant ways of doing it but I'm just going to do it in the most simple fashion and again I just talked about immutability but I will use mutability in order for this just to be as simple as possible what I'm trying to say is that we would probably use a map here rather than a fridge but we're just going to use a fridge so what I would do here is that we can say okay let's start with a string and let's call it HTML so we know that it will contain some things what we know that it will contain is that we know it's a list so we know that we need the UL element then we know that it has a title so that means that we need the li element and then we need we know that we have a title so we need to add that to the li element but then within this Li element we need to add sub list containing all of the li elements so actually I'm getting a bit confused now about whether I drew it incorrectly before let me write the correct implementation as I'm thinking about it now and then let's draw up the li UL example again moment when we see this output in case I drew it incorrectly before so if you have a list it necessarily has to be a project so like the full to-do list if you have only a flat to-do list it will be a project that would be like the project of my life or whatever like all my to dues that project so that means we start with ul so we start with the UL tag and then we want to add a title but in order to add a title we need to have the Li tag because that's the first element so we add the Li tag then we close this string and then we want to add the titles then let's concatenate into the HTML variable into the HTML string so I'll say plus equals to denote concatenation so HTML after this line will be equal to whatever it was before plus this new thing that we're adding in and what we're adding in is this dot title so the title that we've gotten that we've pass them through the constructor and now saved to the instance variable we're adding that into this locally scoped HTML variable that contains the UL and the Li opening tags but nothing else it's a project so it might contain two dues so what do we need to do well essentially we need to iterate through them so let's say for each now we can't say to do because that's a specific type and we can't say project because that's a specific type because what we know is we know to do list we know the general type that both of them can have or that both of them behave as so we say for each to do list let me just call it at TL in this dot - dues this dot - dues it's a bit of funny naming here I should have called that to do lists but sorry about that so for each to-do list TL that we can tell in this dot - dues and then we open open this up sorry what I forgot this before this we need to add we need to further concatenate into the HTML another ul element right because now we're opening up for adding in more list items so we add ul Li the title and then another opening ul tag then we start to iterate and then for each of the things that we find in this list what we do is that we further add to the HTML string HTML + equals and then we add first an opening Li tag let me do this on separate lines to make it super clear HTML + equals here is the super crucial part here's the recursion this is where we - this HTML string and we concatenate whatever we had in the string before in other words HTML with TL don't get HTML in other words we concatenate we add in to whatever we had in the HTML string before in to that we add the result of calling get HTML on this particular TL and this particular TL of course is the variable name that we chose for this variable of type to do list that is the one we are currently at in our inner for each iteration over this dot - duze in other words think about it the project is a composite of to-do lists it's not just a single to do it is a composite of to-do lists which means that it may contain projects or it may contain a single to do so when we say for each to-do list tl in these two dues we will step-by-step get a whole dog or or I should say one by one get a hold of through the situation get a hold of individual to-do lists and these to-do lists are either individual to-do items or they are projects so this project may either contain a series of two dues or a series of projects that have to do or any mix of those and again this is where the recursion comes into play so when we call get HTML on this particular to-do list then that to-do list if it is a to-do then it will simply print the text of that to do but if it happens to not be or to do but rather to have if it happens to be another project then we will end up in the get HTML method of the project again this is what we talked about before when we talked about recursion will end up in the same function in the same get HTML method but in another instance which is this other project instance which is this TL and that that instance intern can have a bunch of to-do lists in itself and so when we call get HTML on that that might cause us to call get HTML on all of its children and so forth and so forth and so forth we're digging our way down so essentially we call this get HTML here and concatenate it into the HTML string what else do we need to do well we need to sort out the 8 HTML here we need to do some closing tag so after we've gotten that HTML we need to close this Li tag so now we're closing this tag right we're closing the list item tag that encapsulates this particular item in the to-do lists that were iterating over within this project and again this to-do list might be so in the simple case these to-do lists would all be to do so we are in the project and we are iterating over all of the DUS that we have and we wrapped them in allies because they are to dues their - there are items that need to be displayed separately but again these might turn out to be projects rather than just to dues and then we will recur again because then we will call get HTML and run this method again but within the context of that project rather than this project but anyways we closed the Li tag here and then we close the foreach because then we need to stop circling around the all of these to-do lists because we're done with what we want to do to each to-do list and then some more concatenation into the HTML string so we concatenate another string that closes the UL tag now we're closing this tag and then we need to I'll do this on the same line we need to also close this Li tag that contained the title essentially and then we need to close the outer UL tag the first UL tag that we had here and then we're done with the HTML and then we can simply say return HTML so we will return this massive string that we've constructed and we'll close to get the HTML method and we will close the whole class because the class is done and now actually I'm realizing back to this point where I said that maybe I did it differently with a ul than the Allies and what I explained over here before when I drew up the HTML actually it's completely unnecessary to say that the title may emphasize this the title here that I wrapped this within a list that had a single element that I then have to close here in here I mean that's actually completely unnecessary probably what we should do is we should just skip this right there's no outer UL element sometimes it's really tricky to think about recursion so what I would do instead I guess is just we would maybe put an h1 let's say right so we make it a header like a proper title so it's an h1 then we add the title and then instead of just opening the UL let's think about it then we immediately close the title we close to h1 and then we open the UL so we open the unordered list then we're into this for each thing where we're printing allies and then we are here when we're out of the fridge we are closing the UL but then there is no need to as we were saying close this Li and closes ul this actually makes a lot more sense so we just close this ul off to do's and if you think about it I mean that kind of makes a lot more sense because what we were saying before is that if you have any particular instance of something that is of type to-do list it can either be a to-do or it could be a project and if it's a to do it just has a text but if you have a project and you ask it for its HTML it will begin by printing the title wrapped within an h1 which I mean it kind of makes a lot of sense and then it will print the list so that's it super quick recap there's an interface called to-do list that both to do's and projects implement so to do's and projects can be used interchangeably adhering to the notion of a to-do list simply requires that you implement a method that returns a string and is called get HTML it takes no arguments and then of course these two classes that to do class and the project class both of these have implementations for the get HTML method and the implementation in the to do is simply that it just prints the text of this particular to do so in the constructor of the to do we take a parameter which is a string which is called text which represents the text of the to do we take that into the instance of the class and then when we call get HTML we simply print that text or a serration say print we return that text as opposed to the project which is a little bit more complex because the idea of the project is that the project is a composite to-do list in other words it contains not only a single to do but it contains multiple to do's and actually by extension multiple projects if you want to be more specific the project is a to-do list behaves as a to-do list sorry not either because of interface Ness I mean it behaves as a to-do list it responds to the interface to do this so you can think of it as is a to-do list but it also has to do lists and in this case we implemented that by saying that it a list over to do lists and we call it to dues here either way this project class then again is a composite to-do list so it contains multiple to-do lists so we said that it that it behaves as and it contains multiple to-do lists and because it contains multiple to-do lists that means that since every to-do list can either be a single to do or another project that means that we can infinitely missed projects within projects because if projects behave like to-do lists and if project can contain to-do lists that means that projects can contain projects so somehow then when we ask a project for its HTML it's not as simple as whether to do where we can simply print the text of that to do what we have to do is we print the title so it's the text of this project but we call it the title sorry now I say printing again but again I mean returning we start by constructing a string that we will return and in this string we will put the title but we need to put more stuff and that stuff is dependent on what's in this to-do list what's in the actual composite what it actually contains so somehow we have to iterate over that collection that we have in this case an ordinary collection so a list and simply this is the recursion ask each of those things for its answer to the method get HTML so when we call get HTML yes we print the title of this particular project but that's not enough we need to also print every to-do list that we have in the instance variable they start to do this in other words in all of the contents of this composite so we iterate over the contents of this column composite we iterate over the objects that it has and for each of those objects we do some particular computation but most importantly we call get HTML and since those objects might also be of type project that means they will also do all of this stuff because they also have to get HTML method and that's the method that we're calling upon them and this is the recursion so you have something of type T and it has another thing that's also of type T and it has another thing that's also of type T and so forth but it's actually I mean it's more again because we have a hierarchy like this so it's more like this thing can have multiple things but if we just think about it simply you can think about it as a decorator pattern right this first thing has a reference to the second thing and the second thing has a reference to the third thing but they're all of the same type so when the first one is asked for get HTML it can't answer it has to do some computation by itself but also merge its own computation with what's ever in the one it has a reference to and that one does some computation by itself actually in the same computation because it's of the same type so it's the method it's the same method but it's in another instance but then again it can't just return immediately because it needs to know what the object that it refers to what it will respond to in its computation so it delegates to the to the next one to its children in this case just to its child but in a case like this to its children and asks them to perform their get HTML computation and merges it it back with what it has and so forth right so so we drill all the way down and then the value propagates all the way up so if you're doing an out so if you're in an algorithm course and they talk about like in order and preorder and postorder and all that stuff this is a way of implementing these these orders in which you traverse a hierarchy because now you can have an algorithm that traverses this whole hierarchy in a particular order such as for example this one first here then here then here then here then here then here then here but there are other ways of traversing this the structure and and many of them can be implemented using the composite pattern the the potential criticism here would be that and I think that's actually raised by the head first book so if you want to know more about that check this out but the potential criticism that could be raised this single responsibility principle because if you think about it what we want to do is that we want to traverse in a particular order and we want to perform some kind of computation so I mean in this case the computation here is that we want to build up the HTML and that's one thing but the traversing is actually another thing so you could think of a scenario where we would separate the true version from the actual HTML building and this is why the head first book actually talks about composite pattern and iterator pattern in the same chapter I separated into two videos because super long man but you could actually do that you could actually separate the the notion of the traversal from the actual algorithm and one of the upcoming videos we will look at iterative pattern we probably won't look at code for traversing something like a composite structure or something like a hierarchical structure but we'll just but we'll talk about it before we wrap this up let me mention one final thing hopefully you can start to see how this can be very powerful in particular scenarios especially if you want to do a sort of computation over the whole hierarchy without writing really complex algorithms and really I mean generally this is the power of recursion like you can identify very simple algorithms that actually give you very complex answers that sounds like overly unnecessarily complex answers that's not what I mean I think you see what I mean so one example here would for example be if we had the check marks if we had the notion of a to-do being done or not done I mean there are multiple ways of implementing this and actually I should say there are multiple ways of stating the requirements I mean we might have different requirements depending on what application we're building but let's say I mean one thing would be that - maybe - duze could be marked as done or not done but you could also envision that maybe projects could be marked as done and not done like I guess the the sort of burning question is can a project be done even if sub to do of a project is not done I mean it's not an insane idea right it could be like well you just we ran out of times we closed this project or we figured out that this to do was unnecessary so we just said nevermind let's just mark the project that's done and move forward it isn't good enough I mean it might be a multitude of different reasons either way if we think about the scenario where only a to-do can be marked as done and a project cannot be individually marked as done maybe then the notion of a project being done is a sort of computed property is an aggregate of of its - duze so if a project is a composite of to-do lists if a project is composed of multiple to-do lists and those to-do lists can be projects or individual - duze let me express this in simpler terms if you have a to-do that has a number of sub - duze what if the notion of that initial to do being done depends on whether all of the sub to do are done so if all of the sub to dues are done that means that that the parent to do is done if any of the sub to dues are not done that means that the parent to do is not done so essentially it's an end operation right we have the parent to do and we join the doneness of all of the sub to dues using the logical and operator so the doneness of the parent is the doneness of the first child and of the second child and of the third child and so forth which means that because we're using the operator and if any of them turn out to be false that means that the the aggregated answer is false and this would be extremely trivial to implement in this scenario so that is done method in in the to do will be super simple right because that's just a property that is changeable by the user right either the to do it's like we have the properties text but then we would also have the property is done and that says whether it's true or not so you have a boolean here which says that it's either done or not or if this was built as an immutable data structure maybe we actually have a ton to do and an undone to do we're not done to do or maybe then it would make more sense to say that we have a to do and we have a completed to do or something like this either way that implementation would be really simple however the project implementation the project's implementation for the for the is done method would not be as simple but it would be fairly trivial in functional programming jargon what we would do is that we would simply map the function get HTML over the collection of to-do lists and then we would reduce using the logical operator and right that's like one line I mean super simple but in non functional programming jargon what we would simply do is that we would we would foreach through all of the two dudes in the to-do list and then we would ask them for their is done and remember when we asked them for their is done they recurse downwards so they asked any objects that they have in case they are composites and then if any of them report back that they are not done then we simply eagerly return false we eagerly return that well this project is apparently not done because there's something down the chain that's not done somebody returned back false we immediately return is we say Falls this is not done and if if none of them do that then we just return true as a default because it apparently this has to be done so that means again that if you have this outer project that has two sub projects and these two sub projects each have two - duze then when we ask this outer project if it's done it will ask well are you done sub project number one and sub project number one will ask its to do number one are you done it will say maybe yes and this one will say maybe yes so then sub project number one will report yes but that's only one part of the problem then this outer one within it's free each or within its map will ask the next one sub project number two are you done and it can't answer it because it's a composite so it asks its to do number one are you done and maybe that says false no it's not no I'm not done then we don't even bother to check this one because we that's why I said eagerly returned so then this sub project one says actually in my fridge I notice that one of my two dues answered faults that I'm not done then I'll just immediately report back up false I'm not done and then we know that this project then is false because we're doing a logical comparison between true and and falls which is clearly false so again hopefully you see how somewhat complex problems suddenly become very trivial because we have an appropriate data structure anyways so I mentioned in the beginning that I will shortly talk about the differences between composite pattern and decorator pattern but this video turned out so long so I think it's best for everyone if we don't do it now instead I will make the next video about exactly that the differences between decorator pattern and composite pattern and also in the beginning I mentioned chain of responsibility pattern but that simply has to go into another video I hope that's okay either way I hope you now feel that the composite pattern kind of makes sense and you can see some of its sort of massive strengths and drawbacks if not or if you're wondering anything or if you have comments or questions about anything or if you think differently about some of these things as usual please do shoot something in the comments and we can discuss it beyond that links to these books are in the description check them out super good books clearly there's a lot more depth to this than what I'm covering in these videos anyways links are in the description beyond that finally you super much for watching remember to subscribe if you want more stuff like this feel free to share this video with somebody who you think might appreciate it and I will see you in the next one
Info
Channel: Christopher Okhravi
Views: 92,231
Rating: 4.9371128 out of 5
Keywords: composite pattern, composite design pattern, design patterns, design pattern, composite, oop, head first: design patterns, design patterns elements of reusable object oriented software, tutorial, c#, java, programming, code
Id: EWDmWbJ4wRA
Channel Id: undefined
Length: 71min 23sec (4283 seconds)
Published: Mon Nov 27 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.