32
October 2003 91.3913 R. McFady en 1 Polymorphism Indirection Pure Fabrication Protected Variations (Law of Demeter) Ch 22: More GRASP Patterns

October 200391.3913 R. McFadyen1 Polymorphism Indirection Pure Fabrication Protected Variations (Law of Demeter) Ch 22: More GRASP Patterns

  • View
    215

  • Download
    0

Embed Size (px)

Citation preview

October 2003 91.3913 R. McFadyen 1

Polymorphism

Indirection

Pure Fabrication

Protected Variations (Law of Demeter)

Ch 22: More GRASP Patterns

October 2003 91.3913 R. McFadyen 2

Problem:

How should we handle alternatives that are based on the class an object belongs to?

We want to avoid the use of conditional If-then-Else logic

Polymorphism

Solution:

Use polymorphic operations

Methods in different classes are given the same name

Different classes may be said to implement the same interface

Subclasses in an inheritance hierarchy override method implementation of a superclass

October 2003 91.3913 R. McFadyen 3

Text page 326-7:

Multiple tax calculators must be supported. Each tax calculator has its behaviour – behaviour varies by type of calculator

Polymorphism

<<interface>>

ITaxCalculatorAdaptor

getTaxes(Sale) : list of TaxLineItems

TaxMasterAdaptor

getTaxes(Sale) : list of TaxLineItems

GoodAsGoldTaxProAdaptor

getTaxes(Sale) : list of TaxLineItems

The names are the same; the implementations differ

October 2003 91.3913 R. McFadyen 4

ITaxCalculatorAdaptor is stereotyped as an interface. An interface is a set of operations – their names and parameters (signature) but no implementation. Implementation is done by the subclasses.

Polymorphism

<<interface>>

ITaxCalculatorAdaptor

getTaxes(Sale) : list of TaxLineItems

October 2003 91.3913 R. McFadyen 5

When calculator receives the message getTaxes, the method defined in the class TaxMasterAdaptor is executed

Polymorphism

calculator:TaxMasterAdaptorgetTaxes(aSale)

The concept of polymorphism arises in GoF patterns: Adapter, Command, Composite, etc.

October 2003 91.3913 R. McFadyen 6

Recall from Composite

Component

Operation()

Leaf

Operation()

Composite

Operation()Other()

*Client

A leaf or a composite have common operations, but their own implementation

October 2003 91.3913 R. McFadyen 7

P. 329+

Problem:

You have a responsibility to assign to a class, but assigning it to a class in the conceptual model causes low coupling and/or high cohesion.

Solution:

Fabricate a class - create a class that is not found in your conceptual model, one that does not necessarily have a business meaning to the business person.

Pure Fabrication

The GoF pattern: Adapter uses the concept of pure fabrication.

October 2003 91.3913 R. McFadyen 8

Example:

Suppose we need to save instances of Sale in a relational database.

To which class in the model do you assign this responsibility?

Since Sale has the information to be saved, Sale would be suggested by Information Expert.

To manage data going to and from a relational database will require a large number of operations … insert, delete, update, select, rollback, commit, buffer management, …

Pure Fabrication

October 2003 91.3913 R. McFadyen 9

Pure Fabrication

The Expert pattern suggests that Sale is the expert, and so should be the class to do this.

There’s a lot involved - save, retrieve, commit, rollback

- what about LineItems? When you save a Sale do you save LineItems too?

We would end up adding a lot to Sale that has nothing to do with Sale-ness … Sale becomes less cohesive and more highly coupled to more non-domain classes. Sale will become much more complex, and not so focused.

October 2003 91.3913 R. McFadyen 10

Pure Fabrication

Pure Fabrication suggests to create a new class for these new responsibilities

PersistentStorageinsert()

delete()

update()

...

Sale remains well-designed - high cohesion, low coupling

PersistentStorage class is relatively cohesive - sole purpose is to store/retrieve objects to/from a relational database

PersistentStorage is a fabrication; it is made up from your imagination; it cannot be found in the Domain Model

October 2003 91.3913 R. McFadyen 11

Pure Fabrication

Example: see pages 73-76 of Patterns in Java, Volume 2; Mark Grand; John Wiley & Sons

Fig 4.13 shows a conceptual model

Fig 4.14 shows an initial assignment of responsibilities, where the ServiceManager does scheduling and invoicing.

Fig 4.15 shows the fabrication of a new class, InvoiceGenerator, which results in higher cohesion/less coupling.

October 2003 91.3913 R. McFadyen 12

System manages a field service organization:

•Organization sends technicians who install and repair equipment on service calls to other organizations that use the equipment

•Some service calls are paid by the organization that uses the equipment; equipment vendors pay from some service calls; others are paid for jointly.

•Service manager is given field service projects for a user organization

•Service manager is schedules service technicians to perform the tasks

•Service manager sends invoices for completed tasks to the paying organizations

October 2003 91.3913 R. McFadyen 13

UserOrganization

PayingOrganization

ServiceTechnician

ServiceManager

FieldServiceProject

Note: ServiceManager is highly coupled to other classes

Organizes-work-for

Install/repair-equipment

schedules

schedules

schedules

invoices

compute-invoices-for

performs

pays-for

1..*

1..*

1..*

1..*1..*

1..*1..* 0..*

0..*

1

1

1

1

11

1

1..*

0..*

ServiceTaskgetPayor():

Patterns in Java, Volume 2 Fig 4.14

October 2003 91.3913 R. McFadyen 14

Consider the tasks assigned to the ServiceManager:

•scheduling tasks

•scheduling projects

•scheduling technicians

•generating invoices

These are central to the function of the service manager

no reasonable class in the domain to assign this to, so using Pure Fabrication, fabricate a new class for this purpose

October 2003 91.3913 R. McFadyen 15

UserOrganization

PayingOrganization

ServiceTechnician

ServiceManager

FieldServiceProject

Organizes-work-for

Install/repair-equipment

schedules

schedules

schedules

invoices

compute-invoices-for

performs

pays-for

1..*

1..*

1..*

1..*1..*

1..*1..* 0..*

0..*

1

1

1

1

11

1

1..*

0..*

ServiceTaskgetPayor():

InvoiceGenerator

generateInvoices():Note: Pure Fabrication preserves low coupling and high cohesion

Patterns in Java, Volume 2 Fig 4.15

October 2003 91.3913 R. McFadyen 16

Object Design Discussion P. 331-2

Behavioural decomposition

•Pure Fabrication can support this

•Classes are determined by behavioural grouping:

•managing persistent storage

•generating invoices

Representational decomposition

•Classes represent real things found in the problem domain - clerks use registers to create sales comprising line items …

•Reduces the representational gap

•Objects do things that, in the real-world, are done to them.

Design of objects divided into two groups:

October 2003 91.3913 R. McFadyen 17

Indirection

Problem:

Classes are highly coupled. How can we assign responsibilities to classes in order to keep coupling low?

Solution:

Assign responsibilities to an intermediate class

Later on, we discuss GoF patterns: Adapter, Façade, and Observer. These incorporate the concept of Indirection

October 2003 91.3913 R. McFadyen 18

Indirection

Figure 22.3:

Objects send messages to the real tax calculators through an intermediary object (an adapter object)

s:Sale :TaxMasterAdapter

<<system>>

: TaxMaster

taxes := getTaxes( s )

t := getTotal()

October 2003 91.3913 R. McFadyen 19

Protected Variations P. 334+

Problem: How do we design systems so that changes in its elements do not have an unfavourable impact on other elements?

Solution: Identify points of predicted variation/instability and assign responsibilities to create a stable interface around them

Example:

Law of Demeter (LoD)

Special case of this pattern. (p. 336+ )

If objects traverse long object structure paths and send messages to distant, indirect (stranger) objects, the system is fragile with respect to changes in the object structures - a common point of instability in systems. LoD helps us avoid creating such designs

October 2003 91.3913 R. McFadyen 20

Law of Demeter

• Also called Don’t Talk to Strangers

• Each class should only use a limited set of other classes: only units “closely” related to the current unit.

• “Each class should only talk (send messages) to its friends.” “Don’t talk to strangers.”

October 2003 91.3913 R. McFadyen 21

Law of Demeter

• Don’t Talk to Strangers places constraints on what objects you should send messages to within a method. Within a method, messages should only be sent to the following objects:

• the this object (or self)

• a parameter of the method

• an attribute of this

• an element of a collection which is an attribute of this

• an object created within the method

October 2003 91.3913 R. McFadyen 22

Law of Demeter

FRIENDS

October 2003 91.3913 R. McFadyen 23

Don’t Talk to Strangers

PaymentRegister Sale

getTenderedAmount()paymentAmount()endSale()enterItem()makePayment()...

becomeComplete()makeLineItem()makePayment()getTotal()getPayment...

The class diagram shows that

•Register knows about Sale, and

•Sale knows about Payments that have been made towards it

add a method to get a payment

Suppose Register needs to find out the amount of the payment

October 2003 91.3913 R. McFadyen 24

Don’t Talk to Strangers

Assume:

Register has a paymentAmount method which returns the current amount tendered for the payment

Sale has a method, getPayment, which returns the Payment instance associated with the Sale

Consider:

In order to return the payment amount, we could have a paymentAmount method in Register such as:

public void paymentAmount()

{

Payment payment = sale.getPayment()

Money amount = payment. getTenderedAmount()

}

A little different from the text’s example

October 2003 91.3913 R. McFadyen 25

Don’t Talk to Strangers

:Payment

:Register :Sale

The previous has messages:

Register will have a dependency on Payment

This increases the coupling in our system

getPayment()

getTenderedAmount()

October 2003 91.3913 R. McFadyen 26

Don’t Talk to Strangers

:Payment

:Register :Sale

If getPayment() in Sale would invoke getTenderedAmount() in Payment, and return the payment amount, then we can de-couple Register from Payment

• make the solution more robust, less sensitive to changes, less coupling

Register will get the payment amount it is after, but it won’t know how it was obtained - see Parnas’ concept of information hiding on page 339

Objects are only sending messages to their friends

getTenderedAmount()

getPayment()

October 2003 91.3913 R. McFadyen 27

Law of Demeter presentation:

•www.ccs.neu.edu/research/demeter/talks/frameworks/ubs/LoD.ppt

Karl J. Lieberherr; Northeastern University

other resources

•www.ccs.neu.edu/research/demeter/

•www.ccs.neu.edu/home/lieber/LoD.html

Article on Information hiding

•www.computer.org/certification/beta/McConnell_Missing.html

October 2003 91.3913 R. McFadyen 28

Example: Applying LoD as system changes

BusRoute BusStopList

BusStopBusList

Bus PersonList

Person

passengers

buses

busStops

waiting

0..*

0..*

0..*

October 2003 91.3913 R. McFadyen 29

BusRoute BusStopList

BusStopBusList

Bus PersonList

Person

passengers

buses

busStops

waiting

0..*

0..*

0..*

Find all persons waiting at any bus stop on a bus route

Collaborating classes:

October 2003 91.3913 R. McFadyen 30

class BusRoute { BusStopList busstops; void printWaitingPassengers () {

busstops->printWaitingPassengers (); }}class BusStopList { BusStop stops[]; void printWaitingPassengers () {

for (int i = 0; i < stops.length; i++) stops[i].printWaitingPassengers ();

} }

Applying Law of Demeter - Partial Java Solution

October 2003 91.3913 R. McFadyen 31

class BusStop { PersonList waiting; void printWaitingPassengers () {

waiting.print (); }}class PersonList { Person people[]; void print () { for (int i = 0; i < people.length; i++) people[i].print (); }}class Person { String name; void print () { System.stdout.println (name); } }

Applying Law of Demeter - Partial Java Solution

October 2003 91.3913 R. McFadyen 32

BusRoute BusStopList

BusStopBusList

Bus PersonList

Person

passengers

busesbusStops

waiting

0..*

0..*

0..*

Suppose the class model is modified to incorporate Villages.

VillageList

Village

villages

0..*

What software changes are needed and still adhere to LoD?