[MUSIC] A common problem in object-oriented systems that design patterns attempt to address is how to reduce the amount of tight coupling. The design principles that are used by all the design patterns define different ways in which coupling can be managed. Less coupling in your system means that your system can be more flexible and is capable of handling changes to its existing code base such as the integration of new features. The design patterns that we have explored make heavy use of generalization generalization, abstraction and polymorphism as means of indirection. While inheritance is a great way to achieve a high amount of code reuse, it comes with the cost of tightly coupling the super class with its subclasses. So, why is there coupling? Think about what inheritance does in object-oriented programming. When a subclass inherits from a super class, the subclass will gain knowledge and access to all of the super classes attributes and methods as long as their access modifiers are not private. This means that if you have multiple levels of inheritance, a subclass at the bottom of the inheritance tree can potentially have a way to access attributes and behaviors of all the super classes. So, what can we do to avoid this? You can use the composing objects principle to gain a high amount of code reuse without using inheritance. This principle states that classes should achieve code reuse through aggregation rather than inheritance. Design patterns, such as the composite design pattern and decorator design pattern use this design principle. Both of these patterns compose concrete classes in order to build more complex objects at one time. The overall behavior comes from the composed sum of the individual objects. An object can reuse and aggregate another object to delegate certain request to it. The idea is that you want to design your system, so that concrete classes can delegate task to other concrete classes. Delegation will provide a loser level of coupling that inheritance. The benefits are clear, but there is a disadvantage to using the composing objects principle. Let's take a look at the advantages first. We have already discussed the primary advantage of the composing objects principle, which is that aggregation and delegation offer less coupling than inheritance. Since the compose classes don't share attributes or implementations of behaviors, they are more independent of each other. They have an arms length relationship, which allows for changes to be made easier. In inheritance, all subclasses of a super class are tightly coupled to that super class. How your classes will compose themselves is determined during the design phase of your development. In the UML class diagram on the left, objects can be composed recursively and uniformly. Or on the right, an object is composed of others that have a consistent type. Composing objects also provides your system with more flexibility. During the design phase, it's easier and more natural to keep classes separated. Composing objects does not force you to try and find commonalities between two classes, and couple them together like with inheritance. Instead, you're able to design classes that can work together without having to share anything between them. This flexibility will also help you if the system requirements change. If you use inheritance, you may have to restructure your inheritance tree. Finally, composing objects allows you to, in effect, dynamically change the behaviors of objects at run time. You can build up a new overall combination of behavior by composing objects. With inheritance, the behaviors of your classes are defined during compiled time. Which means that while you're program is running, they cannot change how they behave. There are an overwhelming number of advantages that composition has over inheritance, but you need to keep in mind the disadvantages as well. The biggest drawback of composition is that you must provide implementations for all behavior without the benefit of inheritance to share code. This means that you night have very similar implementations across classes. With inheritance, you don't need to provide each subclass with their own implementation of a shared behavior. The common implementation is simply accessed within the super class. Needing to provide implementations for every class means that it will take time and resources. A programmer working on providing multiple implementations of the same behaviors means you'll have one less programmer working on other features. The composing objects principle has many advantages over using inheritance to reuse code and build up behaviors in a flexible way. This design principle will help you with reducing coupling in your system by using delegation and by composing objects with each other. In summary, the composing objects principle will provide a means of code reuse without the tight coupling of inheritance. Allow objects to dynamically add behaviors at run time and provide your system with more flexibility. This means less time needs to be spent on system updates. Now, it's not to say that inheritance should never be used. Composing objects in inheritance both have their place. Composing will give you better flexibility and less coupling while maintaining reusability, but that doesn't mean it should always be used over inheritance. You need to examine the needs of your system in order to determine which design principle is appropriate. Do you have a set of related classes or unrelated classes? What is a common behavior between them? Do you need specialized classes to handle specific cases or do you simply need a different implementation of the same behavior? This are the different kinds of questions that you'll need to ask yourself when designing your software systems. By knowing what each design principle recommends, you will understand how to deal with the design issues you will come across.