Presentation is loading. Please wait.

Presentation is loading. Please wait.

GRASP Patterns Best Practices for Object-Oriented Software Design.

Similar presentations


Presentation on theme: "GRASP Patterns Best Practices for Object-Oriented Software Design."— Presentation transcript:

1 GRASP Patterns Best Practices for Object-Oriented Software Design

2 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

3 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

4 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

5 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

6 2. Creator  Give a class A the responsibility of creating instances of another class, B, if: A is an aggregate of B A is a container of B  If no classes apply, 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

7 2. Creator  Whenever one class has the responsibility of creating instances of another class, the two classes are coupled Coupling itself is not wrong, 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, one class becomes dependent upon the other to function correctly

8 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, assigning the creation responsibility to the container or aggregate does not introduce more coupling

9 2. Creator  e.g. Consider an Invoice which has a number of InvoiceItems on it When a new Invoice is created, we might wish to add new items to it It makes sense that the Invoice itself would create instances of InvoiceItem, 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)

10 3. 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, related to instantiation  A good rule of thumb is: If class A is already coupled with class B, 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, this would be contrary to Information Expert)

11 3. 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

12 3. Low Coupling  e.g. Suppose the total price for an Invoice needs to be calculated To achieve this, 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, since coupling will not be increased

13 4. High Cohesion  Assign a responsibility so that cohesion remains high Again, this is vague, 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, than a pattern

14 4. High Cohesion  When about to assign a responsibility, 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

15 4. High Cohesion  e.g. Consider a class Order, 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!

16 4. High Cohesion  To preserve cohesion, Order should not be given this responsibility So what class should persist order details?  Several possibilities exist, but here is one: A matching class (e.g. 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)

17 4. 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

18 4. High Cohesion  By contrast, 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, and thus support teamwork

19 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

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

21 5. Controller  This GRASP is just common sense: When a system event occurs, 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

22 5. Controller  e.g. In a bank system, 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

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

24 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, 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

25 5. Controller  Warning: Watch out for bloated Controllers This can happen if you have one Controller for the entire system, for example Controllers can receive several events, but they should delegate the responsibility of the corresponding functionality to other classes  e.g. The Façade Controller will receive the event, 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

26 5. Controller  View classes generally should not receive system events The reason for this is that when View classes receive system events, 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, the View class actually handling the behaviour would definitely reduce cohesion  The View class would have at least two purposes: user interface and behaviour

27 Coupling  Coupling cannot be avoided altogether Without coupling, 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, 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

28 6. Polymorphism  When related behaviours vary by type (class), 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, and yet another best practice

29 6. Polymorphism  e.g. Consider a UML diagram drawing program  If shapes are responsible for drawing themselves via the draw() method: Obviously, 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.g. State) can be easily added without changing the core graphics code

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

31 7. Pure Fabrication  To support high cohesion and low coupling, 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

32 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, since they are ways companies can preserve resources  Usually, Pure Fabrication is used when there is no appropriate class to use Usually, it is a good idea to try the other patterns first to try to find a solution which more closely resembles the domain entities

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

34 7. Pure Fabrication  Architect might be used to store user preferences, recently created diagrams and projects, etc. 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.g. UseCaseRenderer, ActorRenderer

35 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

36 8. Indirection  To avoid direct coupling between objects, assign an intermediate object as a mediator 1.Recall that coupling between two classes of different subsystems can introduce maintenance problems 2.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

37 8. Indirection  e.g. Consider an application for managing group work Employee instances might need to be coupled to Project instances However, 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, the class represents an association class (a class that represents an association)

38 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, thanks to the Façade

39 9. Protected Variations  Assign responsibility to create a stable interface around an unstable or predictably variable subsystem or component If a component changes frequently, 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

40 9. Protected Variations  e.g. Big video game companies make money by creating a 3D graphics game engine (as well as sound, AI, etc.) These video game companies often produce many games using the same engine, 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, 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

41 9. Protected Variations  These video game companies facilitate additional revenue by making their wrapper modules flexible, so that they can create many games using the same interface Thus, 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, the Façade pattern is also an example of Protected Variations

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

43 9. 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

44 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, as a tendency exists to model all possible relationships

45 10. Don’t Talk to Strangers  Often the domain objects have relationships that need not be modeled in the application However, a common tendency is to model those relationships (with aggregation, 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

46 10. Don’t Talk to Strangers  e.g. Consider a convenience store application  Customers are people, as are Employees Should we model this as inheritance?  In this application, customers are likely anonymous Thus, 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, despite our initial reactions


Download ppt "GRASP Patterns Best Practices for Object-Oriented Software Design."

Similar presentations


Ads by Google