The visitor design pattern provides a method of separating an algorithm on an object and the object's actual class implementation. This allows the programmer to easily follow the open/closed principle;
software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
That is, modifying an entity's behaviour without modifying the underlying source code. Following the open/closed principle provides many quality-related benefits as the original code never changes.
Benefits
Follows the open/closed principle
Allows a new operation to be defined without changing the implementation of the class
A visitor object can have state
Drawbacks
If a new visitable object is added then all visitors need to be modified
Design patterns in software engineering are generic solutions to some commonly occurring problems encountered when creating software. They are incredibly useful tools for both communicating a solution to a problem to other developers and also for saving time solving problems that have already been solved in quite elegant ways. Learning the big design patterns is a also just a great way to improve your skills as a software developer.
The facade design pattern is a very simple pattern that provides a simplified interface to other code that may not be structured the same way. If we look facade up in the dictionary, this is one of the definitions we get:
An outward appearance that is maintained to conceal a less pleasant or creditable reality.
This is the primary purpose of the pattern; to conceal a piece of code that isn't very nice to use and replace it with something better. That's all it is really, a class that calls code elsewhere.
Benefits
Can change a badly-designed or hard to use API into an easy to use API
Can merge multiple APIs into a single API
If all calls to a function are done through a facade then it is very easy to refactor
Drawbacks
Could possibly add unnecessary complexity if overused or used incorrectly
The factory method design pattern attempts to implement the concept of real-world factories within your program. Instead of the object creating itself, the task of creation is given to a 'factory' object.
Factory method effectively encapsulates the creation of objects within another class, one benefit of this is that it allows access to resources or objects that may not be available within the class constructor. For example a UI framework may have a createWidget factory method, this method not only returns the new object but also adds it to the list of widgets to be drawn and updated. This is one of the most common usage examples for factory method.
Benefits
Provides a centralised location for pre- or post-constructor logic
Allows access to resources that may not be available within the class being constructed
Encapsulates the creation of objects
Drawbacks
A factory can only be used for a single family of objects
Can potentially overcomplicate a solution
Factory methods are not as easily identified as constructors are
The decorator pattern allows behaviour to be added to an existing object at runtime. This is achieved by wrapping the object (the component) in another class (the decorator).
Like the delegation pattern, the decorator pattern is similar to inheritance as it extends the functionality of a particular class. The primary difference between decorator and delegation is that the decorator pattern is more flexible, allowing multiple decorators to point to a single component at one time.
Reducing the complexity of an inheritance tree is one of the benefits to this pattern, imagine for example an application that prints a photo with an optional filter, an optional border and an optional rotation. This can be achieved in the following ways:
A single class with a lot of code; Photo
A class for each combination of options; Photo, BorderPhoto, FilterPhoto, RotatePhoto, BorderFilterPhoto, FilterRotatePhoto, BorderRotatePhoto, BorderFilterRotatePhoto
A class with optional decorators; Photo, PhotoFilterDecorator, PhotoBorderDecorator, PhotoRotateDecorator
The decorator pattern is of great use when implementing the open/closed principle, as described below:
software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
So once an application has been built, it should only be extended, not modified. It is particularly useful in a production environment as it reduces the amount of regression testing required. The decorator pattern is great here as it's simple to extend existing components in a completely modular way.
Benefits
Add behaviour to a component dynamically at runtime
Attach multiple decorators to a single component at one time
Completely modular, we don't need to touch the existing component
Can reduce the amount subclasses of a class
Drawbacks
Overuse of the decorator pattern can lead to very abstract and complex code
The delegation design pattern allows an object to delegate one or more tasks to a helper object. Two classes are used to achieve this; the delegate and delegator, both which realise a common interface. A method (or methods) on the interface represent the functionality to be delegated. A call to the delegator calls the matching function on the delegate.
While this seemingly just abstracts away some of the functionality into another class, the real power of this pattern comes when there are multiple delegates. The delegator typically has a method for each delegate that will convert the delegator to use that delegate.
It is useful for understanding to compare the delegation pattern to inheritance. Both are powerful reuse techniques with a few of key differences; inheritance is directly supported by today's object-oriented programming languages and enables the use of polymorphism, whereas the delegation pattern allows the delegate to be changed at run-time.
Benefits
Clearly separates the different sets of functionality
The singleton design pattern enables easy access to a single instance of a class.
Benefits
Makes it very easy to get a single instance of an object globally
Drawbacks
They are effectively just globals, this is not object-oriented design
Can cause concurrency issues if not the singleton is not thread-safe
Can make code hard to follow
Makes unit testing more difficult
From the looks of the benefits and drawbacks you would wonder why you would use a singleton at all, a lot of people even consider it an anti-pattern. My answer to that question is that you should only use this pattern very sparingly and preferably not at all in large projects. You can however save yourself quite a bit of time using them in small projects.
The lazy-loading design pattern provides a means to defer the creation of an object by loading it at the point it is needed. This has both benefits and drawbacks.
Benefits
Save memory by only loading what is needed when it's needed.
Reduce initial load time by deferring execution.
Drawbacks
There may be a delay the first time you need the object you're lazy-loading.
Lazy-loading is often a key feature of ORMs, which perform database queries only when the data is required in order to reduce the amount of data retrieved. This can lead to some issues with certain data not being present, you can usually get around this by explicitly specifying what you need. It is important to understand why this can occur when working with an ORM to prevent obscure bugs.