CSC/ECE 517 Summer 2008/wiki3 2 mb
Assignment
Peruse the Patterns Almanac for additional patterns that seem appropriate to cover in CSC/ECE 517. Explain why the patterns are appropriate for students to learn, and if possible, link to training materials (explanations, examples, etc.) for covering them. Your reviewers should rate your choices on how much value they will add to the course!
Introduction
CSC/ECE 517 students explore numerous design patterns during a semester. This web page discusses five more design patterns that may be appropriate to include within a course regarding object-oriented languages.
Visitor Pattern
Appropriateness: The visitor pattern facilitates the decoupling of an algorithm and the objects that the algorithm is applied to. Multiple visitors, implementing different algorithms, can be applied to a set of objects without having to alter the objects when new algorithms are implemented. Thus, independent visitors can be created that implement different algorithms to act on multiple objects. This is useful when the algorithm must behave differently depending upon the object it is applied to. For instance, a pretty-print visitor may be created to handle a set of classes that have different requirements for printing based upon the class.
Brief Summary:
Intent: Provide a single class that implements an algorithm, which can be applied to many other classes.
Problem: A set of classes need to perform an operation that differs for each of the classes.
Solution: Allow the classes that need to perform a similar algorithm the ability to accept a visitor, and then let the visitor apply an algorithm upon all the classes that need the functionality.
Implementation: Create a class (visitor) capable of performing an algorithm upon many other classes (visitee’s). The visitor will define numerous visit methods, where each method signature will contain a different visitee class parameter that determines which method should be visited. The visitee’s that need to access the visitor class will define an accept method, which takes a visitor as a parameter and then calls the visit method of that class and passes itself as one of the arguments, so the appropriate visit method will be called.
Explanations: The following web sites provide explanations of the visitor pattern.
Wikipedia: Visitor Pattern
SourceMaking: Visitor Pattern
Introduction to the Visitor Pattern
Examples: While most explanation sites include examples, here are a couple more examples of the visitor pattern.
Java Design Patterns Visitor
learntechnology.net
Decorator Pattern
Appropriateness: The decorator pattern provides a way to extend the functionality of a class by wrapping that class with another class, as opposed to subclassing the original class. This allows objects to have their functionality extended at run-time, whereas inheritance must usually occur at compile-time. With this pattern, objects can be wrapped to include the appropriate functionality when needed and those same objects can be re-wrapped to include different functionality as the needs of the object change.
Brief Summary:
Intent: Extend the functionality of a class.
Problem: The functionality of a class needs to be extended, but what type of extension may be required may not be known prior to run-time.
Solution: Use a decorator class to wrap an object, extending the object’s functionality when it is required.
Implementation: Create classes (decorator’s) that implement the same interface as the classes (decoree’s) they are meant to operate upon. When a decoree needs to add additional functionality to its objects, those objects can then be wrapped with the appropriate decorator to modify their functionality when the need for the new functionality arises.
Explanations: Different explanations of the decorator pattern can be found on the following web sites.
Wikipedia: Decorator Pattern
The Decorator Design Pattern
Decorator Pattern
Examples: A few more examples of the decorator pattern.
Decorator Pattern Example
Java Design Patterns
Mediator Pattern
Appropriateness: The aim of the mediator pattern is to reduce coupling between the classes of a software system. Communication between objects is handled by the mediator, thus classes do not have to concern themselves with how they communicate with each other, only with how they communicate with the mediator. When new classes are added to the system, or when existing classes within the system are modified, the manner in which they communicate with the other objects in the system is not important. Only the communication with the mediator may require changes.
Brief Summary:
Intent: Simplify communication between objects within a complex system.
Problem: As more classes are added to a software project the intercommunication between the various objects becomes more complicated, and maintaining the code to perform interactions within the system becomes difficult to oversee.
Solution: Add a mediator to the system that is responsible for handling the communication between objects within the system.
Implementation: Create a class (the mediator) that contains the control logic regarding communication between the various objects of the software system. As new objects are added to the system they must only concern themselves with when they need to update the mediator of state changes, as well as how they respond to request from the mediator.
Explanations: The following web sites provide explanations of the mediator pattern.
Wikipedia: Mediator Pattern
Mediator
SourceMaking: Mediator
Examples: A couple more examples of the mediator pattern.
Java Design Patterns: Mediator
FluffyCat Design Patterns: Mediator
Chain of Responsibility Pattern
Appropriateness: The chain of responsibility pattern is another pattern used to reduce coupling between classes within a software system. This allows the sender of a request to be unaware of the receivers of the request. The sender of a request could explicitly define all of its receivers, but the chain of responsibility alleviates the need for such knowledge of the receivers. Not only does a sender not need to know about receivers, but the receivers may be altered dynamically by adding new receivers, removing existing receivers, or changing the order in which receivers obtain the request.
Brief Summary:
Intent: Allow objects to send request to a variety of receivers without specific knowledge of those receivers.
Problem: An object within a software system may need to send information to another part of the system, yet the object does not wish to define the specific receivers of the message. The object may not even know what the specific receivers are.
Solution: Create a chain of responsibility including multiple objects, each of which may choose to handle the request or pass the request along to the next object in the chain.
Implementation: Create multiple classes (handlers) that are arranged in an order of preferred precedence (chain of responsibility). When classes (request senders) need to have an event handled, they pass their request to the first handler in their chain of responsibility. The request is then examined by the first handler, where it will either be handled by the handler or passed along to the next handler in the chain of responsibility.
Explanations: The following websites contain descriptions of the chain of responsibility pattern.
Wikipedia: Chain of Responsibility Pattern
Chain of Responsibility Pattern in Java
Chain of Responsibility Pattern
Examples: The following links provide a couple more examples of the chain of responsibility pattern.
Java Design Patterns: Chain of Responsibility
Refactoring to Patterns: Chain of Responsibility
Flyweight Pattern
Appropriateness: Many software systems require the creation of many similar objects. If these objects share state data a significant performance increase can be attained by sharing the state data that they have in common. While most of the patterns on this page are concerned with the reduction of coupling, this pattern is concerned with increasing efficiency within a system that must contain numerous objects which share common information.
Brief Summary:
Intent: We want to allow the existence of a large number of similar objects within a system.
Problem: If each object is allowed to maintain a unique copy of information that can be shared, the system will quickly consume more resources than are available.
Solution: Share the information that the objects have in common, so more objects can be created with less overhead.
Implementation: Create an object (flyweight) that can be populated with data for immediate use. Allow objects (full weight) to contain only unique information and the understanding of how to access shared data, within the flyweight object, when the object must be used.
Explanations: The following sites provide explanations for the flyweight pattern.
Wikipedia: Flyweight Pattern
The Flyweight Design Pattern
Flyweight Pattern
Examples: A couple more examples of the flyweight pattern.
Groovy: Flyweight Pattern
Java Design Patterns: Flyweight Pattern
Web Site Reviews
Notice that a treatment of all the design patterns on this page can also be found within the Head First Design Patterns textbook that is required for this course.
Please rate the preceding design patterns on how much value you feel they would add to this course, from 0(no value) to 5(high value).
Hint: Copy and paste the following into your additional comments section and change the numbers to reflect your opinion.
Value Rating
Visitor: 4
Decorator: 5
Mediator: 2
Chain of Responsibility: 3
Flyweight: 4
Addendum
I must apologize to my reviewers for covering design patterns that were in fact covered in the course lectures. Trying to get an early start on this project, I had not viewed the last two lectures regarding design patterns. Therefore, I would like to include more design patterns on this page.
Object Pool Pattern
Appropriateness:
In a system that has objects that are expensive to create, it can be advantageous to create a number of these objects in advance and allow clients to share them. The best description I found for this pattern uses the analogy of a real world library to describe the pattern. It is cheaper to go to the library and borrow a book than it is to purchase the book, just like it may be cheaper for a software client to borrow an object rather than instantiating a new one. Many web sites like to discuss the example of threads within a system. A thread manager creates a number of pools that will be shared amongst clients, thus avoiding the overhead of creating and disposing of the threads.
Brief Summary:
Intent: Clients of a system want to share the use of objects that are expensive to create and cannot exist in large numbers.
Problem: The system cannot support instantiating numerous objects of a certain type or the cost of instantiating a certain object is too expensive, with regard to time and/or space.
Solution: Create a certain number of objects in advance that can then be shared amongst the clients in the system.
Implementation: We create an object pool, also known as a resource pool that will be responsible for creating, sharing, and managing objects. Then when clients wish to use an object within the pool, the object pool will allow them to borrow one of the pre-created objects. The object pool is also responsible for returning the objects to a usable state. That is, if state information was changed in the object borrowed by the client, the pool manager must reset the object to an appropriate state.
Aside: The object pool manager in this pattern is generally implemented with the Singleton pattern. Also, this pattern is similar to the Factory Method pattern since they both create objects. The difference is that the Object Pool pattern is also responsible for the management of those objects.
Explanations:
Wikipedia: Object Pool Pattern
Pattern Summaries: Object Pool
SourceMaking: Object Pool
Examples:
Best Practices Engineering – Object Pool
Build your own ObjectPool in Java to boost app speed
Producer-Consumer Pattern
Appropriateness: Let us suppose that we have a system that needs to coordinate asynchronous usage of objects. That is, we have two independent mechanisms, where one is responsible for creating objects and the other is responsible for using those objects. If the system is synchronous then we can get away with putting both mechanisms within the same loop. But, when they do not operate at the same speed one of the mechanisms will be operating inefficiently as it must wait on the slower operation to complete.
Brief Summary:
Intent: We want to create information or objects within a system that will be used by a client.
Problem: We can create information much faster than the objects can consume it.
Solution: We allow information/object creation to operate independently of information/object consumption.
Implementation: We implement a producer object that is responsible for the creation of data. The producer has access to a queue which it will use to store the information it is creating. We will also implement a consumer or consumer objects that will use the same queue to acquire data when it is ready to handle it. We need to ensure that both the producer and consumer have access to the same queue, while we also want to decouple the access between the producer and consumer. This will not only allow different consumers to access the data, but it will also allow different producers to produce data as needed.
Explanations:
Application Design Patterns: Producer/Consumer
Approco: Applet Producer-Consumer
Examples:
Example: the Producer/Consumer Pattern
The Producer/Consumer Pattern – Java Threads
Immutable Pattern
Appropriateness: Consider the situation where we know that an object will not change its state after it has been created. In this case, it does not make sense for us to allow the object to ever change its state after it has been created. This will enable other objects to use references instead of copies of the objects.. This is when the immutable pattern comes into play.
Brief Summary:
Intent: We want to create objects that will not change after they have been created.
Problem: Accessing these objects in an environment where concurrency is an issue will create unnecessary overhead, via some locking mechanism. Additionally, objects that want to use objects that will never change may make a copy of the object instead of using a reference to it.
Solution: We will decide up front which objects can be changed and which cannot be changed. Those objects that cannot be changed will be accessible only through references, not through copies. Also, when multiple threads wish to access these non-changing objects they can do so safely, as it will not be possible for them to change.
Implementation: We define the fields of objects we do not wish to change to be final. Then when we create the object we must initialize the final fields and they will stay that way until the object ceases to exist within the system.
Explanations:
NationMaster Encyclopedia: Immutable Pattern
Mutable/Immutable Patterns
Pattern Summaries: Immutable
Examples:
Mutable or Immutable?
C# coding solutions: Immutable Types