The composite pattern makes working with tree-like structures much easier. You'll implement and work with a real-world example of a composite in this lesson.
1.Introduction1 lesson, 01:40
2.Creational Patterns2 lessons, 11:52
3.Structural Patterns4 lessons, 33:47
4.Behavior Patterns4 lessons, 36:32
4.1Chain of Responsibility12:12
5.Conclusion1 lesson, 01:06
If you've done any work with any tree like structure, then you can understand why the composite pattern exists. And we're going to look at the file system because that is a pretty good example for a tree structure. So we have the file system, which is of course made up of drives, it's made up of directories and files. And we can refer to the directories as branches, then we can refer to files as leaves. So we essentially have two different types of objects within this tree structure, and we work with them differently. The operations involved with reading a file really doesn't translate to doing anything as far as getting the file system entries within a directory. So when it comes to working with a tree structure like the file system, we typically have to work with two different types of objects. Well, the composite pattern says that we should not do that. If we have a tree-like structure, then the branches and the leaves inside of that tree like structure should be the same type of object so that when it comes to processing all of those objects, that we use the same code for doing that. So guess what we are doing in this lesson? We are going to implement the composite pattern by creating a tree like structure with similar objects. So we're going to use a business structure for our example. We're going to have employees, we're going to have a manager, and then we're also going to have an executive. But all of these are going to be based upon an abstract class called EmployeeAbstract. And this is a relatively simple class. We're going to have a few properties such as the first name, so let's go ahead and do that, protected $firstName. Let's also have a $lastName, and we also need the $position of the employee, so let's have that as well. And then an employee could have some, what I'm going to call underlings, these of course are subordinates. But it depends upon the employee as to whether or not they are going to have any underlings. So a regular employee is not going to have underlings. A manager will, and of course an executive will as well. And of course our underlings array is going to be an array of other employee abstract objects. So now let's write a constructor, and we are going to have our $firstName, the $lastName, and then the $position are all going to be passed to the constructor. And then we of course are going to set our properties to those values. So firstname = $firstName, and let's just copy and paste that and make a few changes there. Now as far as this abstract class is concerned, we're going to have most everything in here. When it comes to writing the actual concrete classes, they're going to be very simple. Because there's a method that we need to implement in each one of those that's going to be called add underling. Because we need to be able to add underlings to an employee. But how we add those employees really depends upon the type of employee that we're working with. So we're going to make this abstract public function, we'll call it addUnderling. And then we are going to accept an EmployeeAbstract object called $underling. And then we also need a way of retrieving our underlings. So let’s make a public function, we’ll just call this underlings and we will return $this->underlings. So, this is our abstract class. And you can begin to see the tree like structure because we have a collection of underlings which are going to be employee abstract objects, then we will be able to walk through our tree of employees. So, now let's write our first concrete class which is going to be executive. This is going to extend the EmployeeAbstract, and all we need to do is implement the addUnderling method. And all we are going to do is just add our object to the underlings array. So EmployeeAbstract, and we call this $underling. And then we will simply say $this->underlings, and then we will add it to the array. So simple as that, and really the manager is going to be almost the exact same. Except that its name is going to be different, Manager. But when it comes to the employee class the only thing we are going to do inside of that underlings is return false. We could do whatever we wanted here but, by returning false, we're just signifying that nope, nothing's gonna happen. So now we can go ahead and create our objects, so we can create a new Executive which is going to be our CEO. Let's name him John Doe. And then the position is going to be CEO. And then let's have a manager. We'll call this the controller, and her name is going to be Jane Doe. They could be related, they could not be, I don't know, who cares. And the controller is her position. Let's also have another manager, we need the itManager. And this dude's name is going to be John Jacobs. So he is a new manager, his first name is John. Although let's make it Jon, J-O-N. And then Jacobs, and then IT Manager. And then we need just a normal employee, so we'll call this an itWorker, this is a normal Employee. For the name, let's name him Tim, and last name Tifford, I apologize that this is actually somebody's name. And he is going to be an IT Grunt, and now we just need to set up our tree. So our CEO is going to be at the top of the tree. And so we're gonna call the addUnderling method, and we're going to pass in the controller, and we're going to call that again, and pass in the itManager. And then we need to add our itWorker to the itManager, so we're going to just use those objects there. And so now we have our tree, it's a pretty small tree, but it's a tree nonetheless. Now we just need to process our tree, and we're going to start by writing a function that is going to output the names of our employees, and then the underlings. And there's a red squiggly here, cannot declare class Execute, which should not be Execute [LAUGH] and because the name is already in use. So that needs to be called Employee and the execute class needs to be Executive. So let's change those class names, great. And then we will write our function. So let's call this echoEmployees. The first thing that we will pass is an employee abstract object. And we'll just call it $employee. And then let's also have a prefix, because as we write these names to the console, we need to show a relationship between an employee and it's underlings. So, we'll have a string called $prefix. And the first thing we will do is output our employee's name. So we will echo, we will take the $prefix, and then the employee. But we didn't write a method for retrieving the name, did we? No, so let's do that. Instead of employee abstract we're going to add a public function called getName. And we will output the first name followed by the last name, and then we will use a comma, and the position so that we have all of the information about this particular employee. So we will use this getName method to get the name, and then we will concatenate a new line so that every new employee will be on a new line. Let's go ahead and update our prefix so that as we iterate over the underlings we can go ahead and pass in the new prefix. Let's use one, two, three spaces, and then we just want to foreach loop to iterate over the $employee->underlings method and that is not a plural. We'll call each variable simply $underling, and we will reuse our echoEmployees function. So the same exact code is going to be used to output each one of the employees. So we'll pass in $underling, we'll pass in $prefix, and that should be it. So let's call our function echoEmployees. At the top of the tree is going to be our CEO, the prefix, just an empty string, and let's run our code. And we get a fatal error. Executive::get() is not there, of course it's not because it's called getName. Let's go back, let's clear it, and then let's run it again. And there we go, we have our list although, the last name is not correct. That should be lastName = $lastName. Okay, so let's run this again. And now we have it right. So we have John Doe, our CEO, at the top. Then we have our managers, and then we have the employees under one of the managers. And of course if we change the, structure so that the controller comes after the IT Manager, it will still keep the formating the same. The controller will appear after the IT manager. Well, it should have, but it helps if you change the right code. If we move the add of controller after IT manager then we will see the IT manager first. But as far as the formating is concerned, it is still going to be the same. And so that is the composite pattern. It says that with a treelike hierarchy we need to have the same type of objects, so that the code for processing those objects are the same. It makes our code much more simple, because we don't have to check what type of object we're working with before we actually work with it. They all have the same API, they all behave the same, so the code for processing is much easier as well.