GRASP Patterns

Best Practices for Object-Oriented Software Design

GRASP Patterns
GRASP: Generalized Responsibility Assignment Software Patterns GRASP patterns are really more accurately described as best practices 
GRASP patterns outline best practices which can be employed in any object-oriented design  These best practices, if used properly, will lead to maintainable, reusable, understandable, and easy to develop software

GRASP Patterns
GRASP patterns describe how to assign responsibilities to classes 
Warning: Grasps tend to be vague

Responsibilities is ³a contract or obligation of a classifier´ (UML definition) 
Responsibilities can include behaviour, data storage, object creation and more  They often fall into two categories: Doing Knowing

1. Information Expert
Assign a responsibility (such as behaviour) to the information expert 
An information expert is the class that has (or has direct access to) the information necessary to fulfill the responsibility

e.g. A responsibility such as handling a deposit (i.e. increase balance) should be assigned to the Account class 
This is because Account contains the account balance as one of its attributes

1. Information Expert This GRASP has the effect of having a class with high cohesion  Cohesion ± the degree to which the information and responsibilities of a class are related to each other Cohesion is improved since the information needed for a responsibility is closely related to the responsibility itself .

Creator Give a class A the responsibility of creating instances of another class.2. B. then assign the responsibility to a class C if:  C records instances of B  C closely uses B objects  C has the initializing data for B . if:  A is an aggregate of B  A is a container of B If no classes apply.

but we want to eliminate certain types of coupling Coupling of classes is a measure of how strongly a class is connected to another class  Whenever two classes are coupled. Creator Whenever one class has the responsibility of creating instances of another class. one class becomes dependent upon the other to function correctly .2. the two classes are coupled  Coupling itself is not wrong.

assigning the creation responsibility to the container or aggregate does not introduce more coupling .2. Creator The Creator GRASP ensures that coupling due to object instantiation only occurs on closely related classes  An aggregate or container of a class is already coupled with that class  Thus.

Consider an Invoice which has a number of InvoiceItems on it  When a new Invoice is created.2. Creator e. we might wish to add new items to it  It makes sense that the Invoice itself would create instances of InvoiceItem.g. and subsequently add them to itself  The effect is that no other classes should need to know about InvoiceItems (at least not for this responsibility) .

this would be contrary to Information Expert) . related to instantiation A good rule of thumb is: If class A is already coupled with class B.3. assign a responsibility for B to the class A  This is only if it is not appropriate to assign the responsibility directly to A (otherwise. Low Coupling Assign a responsibility so that coupling remains low  This is pretty vague. but it means that we try to keep low the number of classes to which a class is coupled  Creator is a more specific case of Low Coupling.

Low Coupling The Low Coupling µpattern¶ is definitely a best practice  It is a good idea to keep coupling low in a design The reasons why Low Coupling is important should be obvious:  With Low Coupling. changes to a class (A) affect fewer classes (the classes coupled to A)  Thus Low Coupling improves the maintainability of a software system  A low coupled class is also easy to understand. since it is often simpler and more cohesive .3.

g.3. since coupling will not be increased . the costs must be totalled of all InvoiceItem instances Recall that the Creator GRASP already recommends that we create instances of InvoiceItem within Invoice  Thus. Invoice is already coupled with InvoiceItem  The responsibility of total price should be assigned to Invoice. Low Coupling e. Suppose the total price for an Invoice needs to be calculated  To achieve this.

High Cohesion Assign a responsibility so that cohesion remains high  Again.4. than a pattern . but it simply means that we should always try to maintain class cohesion  This is another GRASP that is really more like a best practice. this is vague.

ask yourself the following question:  Is this responsibility related to the other responsibilities of this class? If not. there is likely a need to assign the responsibility to another class  This may prompt you to create a new class if other responsibilities exist that are similar/related to this one .4. High Cohesion When about to assign a responsibility.

which stores data about an order that has been placed in an online store  Responsibility: Store the contents of an Order to secondary storage Should this responsibility be added to the Order class?  Are order details and persistence management related concepts?  No!! They are not even close! . Consider a class Order.4.g. High Cohesion e.

OrderDAO) whose responsibility is merely to persist Orders Likely OrderDAO will have some persistence code reuse (from a superclass or some other class or subsystem) . High Cohesion To preserve cohesion.4. but here is one:  A matching class (e.g. Order should not be given this responsibility  So what class should persist order details? Several possibilities exist.

High Cohesion Cohesion is important because incohesive classes are large and cumbersome  Such classes are usually thousands of lines long These classes are difficult to understand and maintain  It is also highly unlikely that a class with so many unrelated responsibilities will be useful in any other context There is little chance of class reuse .4.

cohesive classes represent a single abstraction and responsibilities related to that abstraction  Classes representing a single abstraction could be reused in any context that requires modeling that abstraction  Class reuse is possible when highly cohesive Cohesive classes are easy to maintain  How do you find a bug related to storing order details to the database? OrderDAO Cohesive classes are more modular.4. and thus support teamwork . High Cohesion By contrast.

Cohesion and Coupling Cohesion and Coupling are two of the most important concepts in software design However. they are not completely unrelated:  Highly coupled classes often are not cohesive  A class that has been assigned many responsibilities for many external classes is unlikely to represent a single abstraction .

etc. a Façade Controller)  Representative of the entire use case scenario Do not assign these responsibilities to View classes (windows. Controller Assign the responsibility for receiving and handling a system event message to a class that is either:  Representative of the entire subsystem (e. dialogs.5.g.)  A Controller is never a user interface object .

5. the class who has the responsibility of performing a high level function should receive events indicating it should take place  Often a subsystem will have one or more Controller classes. each designed to handle certain responsibilities Controller responsibilities are usually extremely high-level . Controller This GRASP is just common sense:  When a system event occurs.

In a bank system. Controller e. we might have a Controller that manages all banking transactions (TransactionController)  This class would have methods such as: deposit() withdraw() payBill() transfer()  It makes sense that this class receive the event generated when the teller clicks the µExecute Bill Payment¶ button on the user interface .5.g.

the Controller GRASP has to be slightly modified:  One user interface might generate different types of events than another UI  To solve this problem.5. Layers For these architectures. a View class can catch the event.g. Some variations of the MVC. and generate a high-level event corresponding to the requested behaviour  The Controller would handle this event . Controller Some architectures stress the importance of view/controller separation  e.

where the Façade receives events (as well as method invocation messages) and forwards them to the correct subsystem component for handling  This is essentially the same concept as the Façade described earlier in the course .5. Controller The GRASP mentioned that a Controller that represents an entire subsystem might be called a Façade Controller  This is a variation of Façade.

The Façade Controller will receive the event. but they should delegate the responsibility of the corresponding functionality to other classes e. for example  Controllers can receive several events. Controller Warning: Watch out for bloated Controllers  This can happen if you have one Controller for the entire system.g.5. and send a corresponding message to the correct subsystem component to handle it One global Controller is usually a bad idea  One common practice is to create a Controller for each use case .

the View class actually handling the behaviour would definitely reduce cohesion The View class would have at least two purposes: user interface and behaviour .5. they must call the corresponding method in another class to handle the behaviour  This couples the View with this other class We¶ve already discussed why coupling should be avoided (especially between modules)  Worse yet. Controller View classes generally should not receive system events  The reason for this is that when View classes receive system events.

Coupling Coupling cannot be avoided altogether  Without coupling. specific kinds of coupling should be avoided:  Coupling between two classes internal to two different modules would be a big mistake as the internal details of a module should be hidden . all we could create would be isolated and static classes  Our software wouldn¶t be able to do anything Reducing coupling should be one of the factors taken into consideration when assigning responsibilities Also.

6. and yet another best practice . assign the responsibility polymorphically to the specialization classes  This is basically the purpose of polymorphism. so it is natural for software developers to understand This is not much of a pattern. Polymorphism When related behaviours vary by type (class).

Polymorphism e.g. an Actor (stick figure) will draw itself differently than a UseCase (ellipse)  It might make sense in this case to have the classes themselves handle the drawing by polymorphically overriding the draw() method  An advantage is that new entities (e.6. Consider a UML diagram drawing program If shapes are responsible for drawing themselves via the draw() method:  Obviously. State) can be easily added without changing the core graphics code .g.

type = ³Class´) then drawRectangle(«). « End if This is not highly cohesive.type = ³UseCase´) then drawEllipse(«). Polymorphism Polymorphism can lead to highly cohesive objects Consider the example where some draw() method were implemented similarly to this: If (entity. since it combines unrelated behaviours. and it also strongly couples this object with the shape it draws .6. Else if (entity.

7. where no appropriate class is present: invent one  Even if the class does not represent a problem domain concept This is a compromise that often has to be made to preserve cohesion and low coupling  Remember: the software is not designed to simulate the domain. but operate in it  The software does not always have to be identical to the real world . Pure Fabrication To support high cohesion and low coupling.

since they are ways companies can preserve resources Usually.7. Pure Fabrication Pure Fabrication is a compromise when faced with a choice between modeling the domain and preserving maintainability and class reusability  Software maintainability and reuse are always more important in business. it is a good idea to try the other patterns first to try to find a solution which more closely resembles the domain entities . Pure Fabrication is used when there is no appropriate class to use  Usually.

In the previous example is was suggested that entities in a UML editor draw themselves  However.g. OpenGL. Pure Fabrication e.g.7. The real world suggests that the Architect class draw the entities  This is because architects draw UML diagrams . what if this is a difficult task?  What if the drawing facilities vary depending on what drawing facilities the user has installed? e. DirectX. etc.

7.  This would obviously be a cohesion problem Pure Fabrication would suggest creating a class whose job is to draw the entities  One solution might be to have the Entity instances associate with an instance of EntityRenderer component  There could be a subclass of EntityRenderer for each subclass of Entity e. ActorRenderer .g. Pure Fabrication Architect might be used to store user preferences. etc. recently created diagrams and projects. UseCaseRenderer.

7. Pure Fabrication The difficulty then becomes: how do we associate the entity instances with the right instance of renderer?  This is a problem easily solved by the AbstractFactory pattern. discussed later .

assign an intermediate object as a mediator 1. Indirection To avoid direct coupling between objects. Recall that coupling between two classes of different subsystems can introduce maintenance problems 2.8. Another possibility is that two classes would be otherwise reusable (in other contexts) except that one has to know of the other Coupling the two objects would reduce the reuse contexts to where both abstract concepts were relevant together  The objects could not be reused separately .

potential for reuse of both Employee and Project is high One solution is to assign a class (Assignment) to couple the two classes  In this case. Indirection e.8. the class represents an association class (a class that represents an association) . Consider an application for managing group work  Employee instances might need to be coupled to Project instances  However.g.

thanks to the Façade .8. Indirection The Façade pattern is another example of Indirection  The Façade prevents coupling classes in two different subsystems Classes in one subsystem communicate directly with the Façade  The Façade communicates with the correct subsystem component Thus. changes to the structure of the subsystem will not affect the user of the subsystem.

the users of the component will also have to be modified  This is especially time consuming if the component has many users Wrapping the component in a stable interface means that when variations occur. the wrapper class need only be changed  In other words. changes are localized . Protected Variations Assign responsibility to create a stable interface around an unstable or predictably variable subsystem or component  If a component changes frequently.9.

AI.9. Protected Variations e. Big video game companies make money by creating a 3D graphics game engine (as well as sound. the wrapper object will have to delegate 3D graphics drawing to different console-level commands  However. the wrapper is simpler to change than the entire game and all of its facets .g.)  These video game companies often produce many games using the same engine. etc. and release the game on many consoles This is only possible to this extent using Protected Variations  If a game is to be ported to another console.

9. so that they can create many games using the same interface  Thus. Protected Variations These video game companies facilitate additional revenue by making their wrapper modules flexible. the Façade pattern is also an example of Protected Variations . a good practice is to leave out unnecessary details in wrappers  It is often useful to try to preserve the cohesion (and thus reuse factor) of a subsystem by keeping the interface flexible Obviously.

which adapts one interface for another Perhaps an application (e. Protected Variations One popular pattern using Protected Variations is the Adapter  An Adapter is another pattern.g.g. OpenGL for 3D graphics) The application (game) might need to be adapted to also run on other platforms (e. DirectX/Direct3D)  An Adapter is intended for this kind of application An OpenGL-to-Direct3D adapter is possible .9. a game) is written to use a one interface (e.g. discussed later.

Protected Variations Among other examples are JDBC and ODBC:  These are packages that allow applications to access databases in a DB-independent way In spite of the fact that databases all use slightly different methods of communication It is possible due to an implementation of Protected Variations  Users write code to use a generic interface An adapter converts the generic method calls to DB-specific communications and vice versa .9.

as a tendency exists to model all possible relationships .10. Don¶t Talk to Strangers Do not couple two objects who have no obvious need to communicate  This is common sense: do not add coupling where unnecessary Again. this is a best practice in software  Although common sense. this still must be considered seriously.

10. a common tendency is to model those relationships (with aggregation. Don¶t Talk to Strangers Often the domain objects have relationships that need not be modeled in the application  However. for instance) anyway Model relationships only if they are necessary to complete a use case  Ultimately it is not relationships in the domain that determine if relationships in software should be present .

Employee instances (which likely store names and phone numbers) do not share any common data or behaviour It makes sense that we not model this relationship. customers are likely anonymous  Thus. Consider a convenience store application Customers are people. as are Employees  Should we model this as inheritance? In this application. Don¶t Talk to Strangers e.10.g. despite our initial reactions .

Sign up to vote on this title
UsefulNot useful