Reposted with permission from the original author
Ezequiel Cuellar of CrossLogic Corporation http://www.crosslogic.com
Section 6 - Design and Implementation Techniques.
Use Case Realizations.
- A use-case realization describes how a particular use case is realized within the design model in terms of collaborating objects.
- Use-case realization work is a design activity.
- Interaction diagrams and patterns apply while doing use-case realizations
- During elaboration use-case realizations may be created or the most architecturally significant or risky scenarios of the design. However, UML diagramming will not be done for every scenario and not in complete and fine-grained detail. The idea is to do interaction diagrams for the key use-case realizations.
- During construction use-case realizations are created for remaining design problems.
Mapping designs to Code.
- Classes need to be implemented and ideally fully unit tested from least-coupled to most-coupled.
- Unit testing code is written before the code to be tested and the developer writes unit testing code for all production code. The basic rhythm is to write a little test code, then write a little production code, make it pass the test, then write some more test code and so forth.
Start Up design.
- Most of the systems have a Start Up use case and some initial system operations related to the starting up of the application.
- The development of an iteration diagram for a Start Up operation must be designed last after all other system operations have been considered. This ensures that information has been discovered concerning the initialization activities required.
- Responsibilities are related to the obligations of an object in terms of its behavior. Basically, responsibilities are of the following two types:
- Doing: Doing something itself such as creating an object or doing a calculation, initiating action in other objects, controlling and coordinating activities in other objects.
- Knowing: Knowing about private encapsulated data, knowing about related objects. Knowing about things it can derive or calculate.
- Responsibilities are assigned to objects during object design while creating interaction diagrams.
- The translation of responsibilities into classes and methods is influenced by the granularity of the responsibility.
- A responsibility is not the same thing as a method, but methods are implemented to fulfill responsibilities.
- Is a named description of a problem and solution that can be applied to new contexts.
- The structure of a pattern is:
- Pattern Name:
- The problem It Solves:
- GRASP patters stand for General Responsibility Assignment Software Patterns and describe fundamental principles of object design and responsibility assignment.
- Patterns are applied during the creation of interaction diagrams. Applying patterns during the creation of interaction diagrams usually leads to the discovery of new domain objects.
Information Expert (or Expert) pattern.
- Problem: What is the general principle of assigning responsibilities to objects.
- Solution: Assign a responsibility to the information expert.
- The information expert is the class that has the necessary information to fulfill the responsibility. The information expert pattern is about assigning responsibilities to this class.
- The first step to apply this pattern is to identify the information expert(s) classes.
- If there are relevant classes in the Design Model, this is the place where we should look first. Else we should look in the Domain Model and attempt to use (or expand) its representations to inspire the creation of corresponding design classes.
- The fulfillment of a responsibility often requires information that is spread across different classes of objects. This implies that there are many partial information experts who will collaborate in the task.
- With the information expert the information encapsulation is maintained since objects use their own information to fulfill the tasks. This usually supports low coupling.
- Behavior is distributed across the classes that have the required information, thus encouraging more cohesive "lightweight" class definitions that are easier to understand and maintain.
- Related patterns are low coupling and high cohesion.
- The Information Expert should be an early pattern considered in every design unless the design implies a controller or creation problem.
- Problem: Who should be responsible for creating a new instance of some classes.
- Solution: Assign a class B the responsibility to create an instance of class A if one or more of the following is true.
- B aggregates A objects,
- B contains A objects,
- B records instances of A objects,
- B closely uses A objects,
- B has the initializing data that will be passed to A when it is created (thus B is an Expert with respect to creating A).
- B is a creator of A objects.
- Low coupling is supported which implies lower maintenance dependencies and higher opportunities for reuse.
- Related patterns are low coupling, Factory and Whole-Part.
Low Coupling pattern.
- Problem: How to support low dependency, low change impact and increased reuse.
- Solution: Assign responsibility so that coupling remains low.
- Coupling is a measure of how strongly one element is connected to, has knowledge of, or relies on other elements. An element with low (or weak) coupling is not dependent on too many other elements.
- In practice the level of coupling alone can't be considered in isolation from other principles such as Expert and High Cohesion.
- Low coupling is a principle to keep in mind during all design decisions.
- A subclass is strongly coupled to its superclass. The decision to derive from a superclass needs to be carefully considered since it is such a strong form of coupling.
- A class with low coupling is not affected by changes in other components, is simple to understand in isolation and convenient to reuse.
- Related patterns are Protected Variation.
High Cohesion pattern.
- Problem: How to keep complexity manageable?
- Solution: Assign a responsibility so that cohesion remains high.
- Cohesion is a measure of how strictly related and focused the responsibilities of an element are. An element with highly related responsibilities and which does not do a tremendous amount of work has high cohesion.
- A class with high cohesion has a relatively small number of methods with highly related functionality and does not do too much work. It collaborates with other objects to share the effort if the task is large.
- A class with low cohesion does many unrelated things or too much work. Such classes suffer from the following problems:
- Hard to comprehend,
- Hard to reuse,
- Hard to maintain,
- Constantly affected by change.
- In practice the level of cohesion alone can't be considered in isolation from other responsibilities and other principles such as Expert and Low Coupling.
- High cohesion is a principle to keep in mind during all design decisions.
- Modular Design, modularity is the property of a system that has been decomposed into a set of cohesive and loosely coupled modules.
- Bad cohesion usually begets bad coupling and vice versa.
- A class with high cohesion is clear and ease of comprehension, its maintenance and enhancements are simplified, low coupling is often supported.
- When there are alternative design choices take a closer look at the cohesion and coupling implications of the alternatives and possibly a the future evolution pressures on the alternatives. Choose an alternative with good cohesion, coupling and stability.
- Problem: Who should be responsible for handling an input system event?
- Solution: Assign the responsibility for receiving or handling a system event message to a class representing the overall system or a use case scenario within which the system event occurs.
- A controller is a non-user interface object responsible for receiving or handling a system event. A controller defines the method for the system operation.
- It is desirable to use the same controller class for all the system events of one use case. Different controllers may be used for different use cases.
- A controller delegates to other objects the work that needs to be done. It coordinates or controls the activity. It does not do much work itself.
- The first category of controller is a facade controller representing the overall system. Facade controllers are suitable where there are not too many system events or it is not possible for the GUI to redirect system event messages to alternating controllers.
- The second category of controller is a use-case controller; in this case there is a different controller for each use case.
- The controller pattern increases the potential for reuse and pluggable interfaces.
- Related patterns are Command, Facade, Layers and Pure Fabrication.
- Problem: How to handle alternatives based on type? How to create pluggable software components?
- Solution: When related alternatives or behaviors vary by type (class), assign responsibilities for the behavior (using polymorphic operations) to the types for which the behavior varies. Do not test for the type of an object and use conditional logic to perform varying alternatives based on type.
- Polymorphism has several related meanings. In this context it means "giving the same names to services in different objects".
- In this pattern an interface that contains the services of the type is created and several adapters classes implement this interface providing their own implementation for the services. When a message is sent to one of these adapters, the adapter applies its own method implementation.
- Extensions required for new variations are easy to add, new implementations can be introduced without affecting clients.
- Related Patterns are Protected Variations, Adapter, Command, Composite, Proxy, State and Strategy.
Pure Fabrication pattern.
- Problem: What object should have the responsibility when you do not want to violate High Cohesion and Low Coupling.
- Solution: Assign a highly cohesive set of responsibilities to an artificial or convenience class that does not represent a problem domain concept, something made up to support high cohesion, low coupling and reuse. Such class is a fabrication of the imagination. Ideally the responsibilities assigned to this fabrication support high cohesion and low coupling.
- Pure Fabrication is chosen by beheavioral decomposition.
- High Cohesion is supported because responsibilities are factored into a fine grained class that only focuses on a very specific set of related task.
- Reuse potential may increase.
- Related Patterns are: Low Coupling, High Cohesion, Expert Pattern, All GoF patterns.
- Problem: Where to assign a responsibility to avoid direct coupling between two or more things? How to decouple objects so that low coupling is supported and reuse potential remains higher?
- Solution: Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled. The intermediary creates an indirection between the other components.
- Lower coupling between components.
- Many indirection intermediaries are Pure Fabrications.
- Related Patterns are Protected Variations, Low Coupling, Pure Fabrication.
Protected Variations pattern.
- Problem: How to design objects, subsystems and systems so that the variations or instability in these elements does not have an undesirable impact on other elements.
- Solution: Identify points of predicted variation or instability; assign responsibilities to create a stable interface (or protection mechanism) around them.
- Data encapsulation, interfaces, polymorphism, indirection and standards are motivated by PV.
- Technology like Service Lookup is an example of PV because clients are protected from variations in the location of services using the lookup service.
- Externalizing properties in a property file is another example of PV.
- Extensions required for new variations are easy to add.
- New implementations can be introduced without affecting clients.
- Coupling is lowered.
- The impact of cost of changes can be lowered.
- Related patterns are most of the GoF.
Adapter (GoF) pattern.
- Problem: How to resolve incompatible interfaces or provide a stable interface to similar components with different interfaces?
- Solution: Convert the original interface of a component into another interface through an intermediate adapter object.
- Adapters use interfaces and polymorphism to add a level of indirection to varying APIs in other components.
- The adapter class that emerges during the enforcement of the Polymorphism pattern is and example of the adapter pattern.
- An adapter wraps access to another system with a single object.
Factory (GoF) pattern.
- Problem: Who should be responsible for creating objects when there are special considerations such as complex creation logic, a desire to separate the creation responsibilities for better cohesion and so forth?
- Solution: Create a Pure Fabrication object called Factory that handles the creation.
- A Factory can handle fabrication of several different types of objects. I can have different creation methods each one for the related type.
- Factories are often accessed with the Singleton pattern.
- Separation of Concerns means to modularize or separate distinct concerns into different areas so that each has a cohesive purpose.
Singleton (GoF) pattern.
- Problem: Exactly one instance of a class is allowed, it is a singleton. Objects need a global and single point of access.
- Solution: Define a static method of the class that returns the singleton.
- The static method of the singleton should be named "getInstance()".
- A singleton is represented in an interaction diagram using a stereotype <<singleton>>. By doing this is not necesary to explicitly show the getInstance() message before sending a message to the singleton instance.
Strategy (GoF) pattern.
- Problem: How to design for varying but related algorithms or policies? How to design for the ability to change these algorithms or policies?
- Solution: Define each algorithm/policy/strategy in a separate class with a common interface.
- The interface for the Strategy Object must accept as a parameter a reference of the Context Object.
- A Strategy object is used only by one Context Object.
- When a Context Object sends a message to the Strategy object a reference of the Context Object must be passed as a parameter for further collaboration.
- The Context Object must use a reference to the Strategy interface (no to the Strategy implementation) to send messages.
Composite (GoF) pattern.
- Problem: How to treat a group or composition structure of objects the same way (polymorphically) as a non-composite (atomic) object?
- Solution: Define classes for composite and atomic objects so that they implement the same interface.
- A Composite is an extension of the Strategy pattern. In a composite a Strategy super class contains a collection of all the strategies. All the Strategies implement the same interface and each one extends from the super class.
Facade (GoF) pattern.
- Problem: A common unified interface to a disparate set of implementations or interfaces such as within a subsystem is required. There may be undesirable coupling to many things in the subsystem or the implementation of the subsystem may change. What to do?
- Solution: Define a single point of contact to the subsystem a facade object that wraps the subsystem. This facade object presents a single unified interface and is responsible for collaborating with the subsystem components.
- A Facade is a "front end" object that is the single point of entry for the services of a subsystem. The implementation and other components of the subsystem are private and can't be seen by external components.
- Facades are often accessed via Singleton.
- The Facade hides a subsystem behind an object.
Observer/Publish-Subscribe/Delegation Event Model (GoF) pattern.
- Problem: Different kinds of subscriber objects are interested in the state changes or events of a publisher object and want to react in their own unique way when the publisher generates an event. Moreover, the publisher wants to maintain low coupling to the subscribers. What to do?
- Solution: Define a "subscriber" or "listener" interface.
- Subscribers implement this interface.
- The publisher can dynamically register subscribers who are interested in an event and notify them when an event occurs.
- One publisher can have many subscribers for an event.
- Ezequiel Cuellar - prime