40
Object-Oriented Analysis and Design CHAPTER 18: GRASP PATTERNS - EXAMPLES 1

Object-Oriented Analysis and Design CHAPTER 18: GRASP PATTERNS - EXAMPLES 1

Embed Size (px)

Citation preview

1

Object-Oriented Analysis and DesignCHAPTER 18: GRASP PATTERNS - EXAMPLES

2

What will we learn?GRASP – Object Design Examples

Applying GRASP to our case studies

3

OverviewWe will practice assigning responsibilities, using the GRASP principles we have learnedBefore we apply the GRASP principles to Domain Objects, we first need to look at how to design the Domain Objects for an entire use case scenario

Use Case Realization: How a use case is realized in the Design Model in terms of collaborating objects

This connects the requirements (expressed in a use case) and the object design that satisfies the requirements

4

Getting Started …The use case suggests system operations that are shown in the SSDsThe system operations become the starting messages entering the Controllers for the domain layer interaction diagramsDomain layer interaction diagrams illustrate how objects interact to fulfill the required tasks and meet the responsibility defined by the system operation – this is the use case realization

5

NextGen POS – Getting StartedRecall that for the basic Process Sale use case, the SSD gave us the following system operations:

makeNewSaleenterSaleendSalemakePayment

These will be the starting messages into the Domain Layer controller objectWe can also consider the Operation Contracts we developed to further help explain how the system changes with these operationsWe will assign the responsibility of handling these system operations to various objects in the Domain Layer – this is RDD

6

Initialization?Shouldn’t we first design a “Start up” use case to initialize the objects, i.e. “turn the system on”?Not a bad idea, and when coding this is often the first thing doneBut in design, we usually do this last, once we know all the objects that will make up the designSo we will first explore the Process Sale use case, and leave the details of a Start Up use case until later

7

Process Sale: makeNewSaleWe start with the makeNewSale system operation – this occurs when the Cashier initiates a request to begin a new saleRecall we had an operations contract for this operation, which had the following post conditions:- A Sale instance s was created - s was associated with the Register- Attributes of s were initialized

We need to define a Domain Layer object to receive the makeNewSale message that occurs when this system operation is started

8

Process Sale: makeNewSaleWe could look to the Domain Model, and consider Store or Register. We could also create a special handler class to deal with this use caseSince this use case has few system operations, defining a new handler class is probably not needed – we can use an existing Domain Object without overloading it (losing cohesion)Defining a Register software object makes sense, since it can handle the few system operations, and is related to the Domain Model object that hosts the softwareSo we have decided that there will be a Register object, and this object will handle the responsibility of processing the makeNewSale system operation - we have made our first design decision!

9

Process Sale: makeNewSaleNote the operation contract mentions that a new Sale object is created; applying the GRASP Creator principle, we look to find an object that can contain, aggregate, or record the SaleAgain, looking in the Domain Model, it appears the Register object meets the need (a register literally means to “register” sales)Also recall that the Sale object was a composite of SalesLineItem objects in the Domain ModelAt this point, we can decide to initialize an (empty) collection of SalesLineItem objects, to be filled in later as the sale is processedAgain, the Creator principle implies that the Sale object is the likely creator for this list …

10

:Register

makeNewSale

:Salecreate

Register creates a Sale by Creator

create lineItems :List<SalesLineItem>

by Creator, Sale creates an empty collection (such as a List) which will eventually hold SalesLineItem instances

by Creator and Controller

this execution specification is implied to be within the constructor of the Sale instance

11

Process Sale: enterItemThis system operation occurs when the Cashier enters an itemID and possibly a quantity for an item in the sale. The postconditions in the operations contract were:- A SalesLineItem instance sli was created- sli was associated with the current Sale- sli.quantity became quantity- sli was associated with a ProductDescription, based on itemID match

We will now walk through the design decisions required to handle this system operation

12

Process Sale: enterItemController: Based upon what we decided earlier, the Register will handle this incoming messageNote the original use case mentioned that the description and price for the item are displayed

By Model-View separation, we generally do not allow Domain Objects to be involved in output tasks, so we will not worry about this requirement right now

Operations Contract states that a new SalesLineItem is createdBased upon the Domain Model, it appears that the Sale object would be the likely candidate to create the new SalesLineItem

Postcondition implies that SalesLineItem needs a quantity when created, and this is derived from the original system operation (input by Cashier)Register must pass this parameter to Sale, which must pass it in the creation message to SalesLineItem

13

Process Sale: enterItemNote that we also need to associate a ProductDescription with this item, based upon the itemID entered by the Cashier and included in the system operation handled by the Register

Who should do the lookup – who gets this responsibility? I.e., who should have the responsibility for knowing a ProductDescription based on an itemID match?This is an application of the Expert GRASP principleQuestion: Who knows the most about the ProductDescription objects? Looking at the Domain Model, we see it is the ProductCatalog

Next design decision: We should have an object called ProductCatalog that will contain the objects ProductionDescription.Then, ProductCatalog is a good candidate to take responsibility for looking up the ProductDescription based on the itemID.

Let’s call the method generated to meet this responsibility getProductDescription

14

Process Sale: enterItemWho sends the getProductDescription message to the ProductCatalog?

Recall that in the Domain Model, Product Catalog was not really associated with any other objectCould use Register or Sale?Note that Sale is temporary, gets created each time a new sale is started, so it would need to be associated with the ProductCatalog each time it is createdRegister is a better choice – can be associated with ProductCatalog upon instantiated; both objects probably instantiated once upon start up

Note that for an object to send a message to another object, it must have “visibility” to itFinal design for this system operation is given on the next slides

15

2: makeLineItem(desc, qty)enterItem(id, qty)

1: desc = getProductDesc(id) 2.1: create(desc, qty)

1.1: desc = get(id)

:Register :Sale

:ProductCatalog

sl: SalesLineItem

lineItems : List<SalesLineItem>

: Map<ProductDescription>

2.2: add(sl)

by Expert

by Controllerby Creator

add the newly created SalesLineItem instance to the List

16

SalesLineItem

quantity : Integer

...

ProductCatalog

...

getProductDesc(...)

ProductDescription

description : Textprice : MoneyitemID: ItemID

...

1..*

1..*

Register

...

enterItem(...)...

Sale

isComplete : Booleantime : DateTime

makeLineItem(...)...1

1

1

catalog

currentSale

descriptions{Map}

lineItems{ordered}

description

17

Process Sale: endSaleThe endSale system operation occurs when the Cashier presses a button indicating the end of entering line items into a sale. Who is responsible for handling this operation?

The postcondition in the Operation Contract states: Sale.isComplete became trueIn other words, this system operation modified a attribute

Again, based upon out earlier design decision, the Register is the controller that will initially receive the system operation message endSaleWho sets the attribute?

Using the Expert principle, the Sale should do thisHave the Register send a becomeComplete message to the Sale (same as a “set” method for the attribute

18

:RegisterendSale( s :Sale1: becomeComplete

by Expertby Controller

19

Process Sale: Calculate Sale TotalThe use case for Process Sale has these steps in the Main Success Scenario:

3. Customer arrives4. Cashier tells System to create new sale5. Cashier enters item identifier6. System records sale line item …Steps 5-6 repeat until no items left7. System presents total with taxes calculated

Question – how does the system calculate the total? Who is responsible for this?

Note that this is a behavior captured in a use case, not a system operation from an SSD

20

Process Sale: Calculate Sale TotalFor this responsibility, we can go right to the Expert principle, since there is no initial system operation to handle for the controllerThe Sale object is the obvious expert object to handle this responsibility

The information required to compute the total is the sum of the subtotals for each line itemThe SalesLineItem knows the subtotal of the line item, and the Sale contains the SalesLineItemsEach subtotal is the line item quantity times the product price (part of product description)The SalesLineItem knows the quantity of the line item, and the ProductDescription knows the price of each itemEach SalesLineItem is the expert that can compute the subtotal, if it is associated with a ProductDescription to get the priceEach ProductDescription is the expert best suited to provide the price for each product

21

:Saletot = getTotal 1 * [i = 1..n]: st = getSubtotal

:ProductDescription

1.1: pr = getPrice

lineItems[ i ]: SalesLineItem

by Expert by ExpertUML: note the selector notation to select elements from the lineItems collection

22

Process Sale: Calculate Sale TotalYou can follow this communication diagram and see how the system would handle the responsibility of calculating the sale total. Note the low coupling!Note that this was not triggered by a known system operation

The getTotal message will probably be sent from some object in the UI, probably after the Cashier hits the button that indicates the end of the sale

It is also possible to include some text in the diagram to indicate how the getTotal method will do the calculation

Note that we have left off the taxes for now

23

:Saletot = getTotal 1 *[ i = 1..n]: st = getSubtotal

:ProductDescription

1.1: pr = getPrice

lineItems[ i ] :SalesLineItem

«method»public void getTotal(){ int tot = 0; for each SalesLineItem, sli tot = tot + sli.getSubtotal(); return tot}

24

Process Sale: makePaymentThe makePayment system operation occurs when the Cashier enters the amount of cash given for the Sale (recall we are only looking at the first iteration here)Here are the postconditions from the Operations Contract:- A Payment instance p was created- p.amountTendered became amount- p was associated with the current Sale- The current Sale was associated with the Store (logging)

Question: Who is responsible for handling this system operation?

25

Process Sale: makePaymentAgain, the Register will handle the initial makePayment messageWho creates the Payment instance p?

Best candidates are Register (in the Domain Model, the actual register would record the payment information) and Sale (has the Total Amount)Note Register will have the amountTendered parameter it received in the system operation

Guideline: When the Expert principle does not give a clear winner, consider coupling and cohesion

From this perspective, we are probably better off letting the Sale object create the Payment instance – makes Register simpler, reduces couplingRegister can pass the amountTendered (called cashTendered in the next slide) to the Sale

26

1: makePayment(cashTendered)

1.1: create(cashTendered)

:Register :Sale

:Payment

makePayment(cashTendered)

by Controller by Creator and Low Coupling

27

Process Sale: Logging the SaleThe last postcondition notes that the Sale is logged with the StoreThis is not a creation or attribute modification – it is an association that is formedNote we can associate the Sale with a Store object, or we can use a SalesLedger object (not defined in the original Domain Model, but probably a good enhancement)Either object will contain a list of completed sales, and the object will add to that list

28

Store

...

addSale(s : Sale)...

SalesLedger

...

addSale(s : Sale)...

Store is responsible for knowing and adding completed Sales.

Acceptable in early development cycles if the Store has few responsibilities.

SalesLedger is responsible for knowing and adding completed Sales.

Suitable when the design grows and the Store becomes uncohesive.

Sale

...

...

Sale

...

...

Logs-completed Logs-completed

* *

1 1

29

1: makePayment(cashTendered)

1.1: create(cashTendered)

:Register s :Sale

:Payment

makePayment(cashTendered)

:Store

2: addSale(s)

completedSales: List<Sale>

2.1: add(s)

by Expert

note that the Sale instance is named's' so that it can be referenced as a parameter in messages 2 and 2.1

30

Process Sale: Calculating the BalanceFinally, we need to decide who handles the responsibility of calculating the balanceThis is the difference between the total for the sale and the amount tendered (cash given by the customer)Apply the Expert principle: Who has the best knowledge to handle this?

Sale and Payment are the most likely candidates – each has one piece of the information needed

What is the visibility of these two objects? Sale created Payment, so it knows about Payment; Payment does not know about SaleBest option: Let Sale do the calculation

31

s :Sale pmt: Payment1: amt = getAmountbal = getBalance

2: t = getTotal

{ bal = pmt.amount - s.total }

32

SalesLineItem

quantity : Integer

getSubtotal()

ProductCatalog

...

getProductDesc(...)

ProductDescription

description : Textprice : MoneyitemID: ItemID

...

Store

address : Addressname : Text

addCompleteSale(...)

Payment

amount : Money

...

1..*

1..*

Register

...

endSale()enterItem(...)makeNewSale()makePayment(...)

Sale

isComplete : Booleantime : DateTime

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

1

1

1

1

1

1

*

catalog

catalog

register

currentSale

descriptions{Map}

lineItems{ordered}

payment

completedSales{ordered}

description

33

Process Sale: Connecting UI and Domain LayerThe objects in the UI need to obtain visibility of the objects in the Domain Layer that they interact with

Java main() that creates the objects in the UI and Domain layers and passes the domain objects to the UI objectsThe UI objects can obtain the Domain objects from a known source in the Domain layer that is responsible for creating the Domain objects

Once the UI objects have been connected to the Domain Layer objects, they can forward system operations to be handledTo get the running total for the Sale to display in the UI object, we could …

Add a getTotal method to Register, and have the Register get this from Sale (lowers cohesion)Have the UI object access the getTotal method of the Sale directly (increased coupling)

34

:Register

Cashier

:ProcessSaleJFrame

actionPerformed( actionEvent )

1: enterItem(id, qty) system event

UILayer

DomainLayer

presses button

35

:Register

Cashier

:ProcessSaleJFrame

actionPerformed( actionEvent )

1: enterItem(id, qty)

2 [no sale] : s = getSale : Sale

UILayer

DomainLayer

s : Sale

3: t = getTotal

presses button

36

InitializationHow do we start up the system?Somewhat dependent on language and operating system …There is usually an initial domain object (or set of objects) that are the first ones createdNote that some objects will create others (Store creates Register in the above model), so these new objects can then be passed to other objects as they are createdGuideline: Choose an initial domain object at or near the root of the containment or aggregation hierarchy of domain objects.

Look for an object that can be considered to contain all or most of the other objects

37

InitializationReviewing the DCD, we can conclude the following sequence of steps (these would be executed as part of main(), for example, in this order):

Create a Store, Register, ProductCatalog, and ProductDescriptionsAssociate the ProductCatalog with ProductDescriptionsAssociate Store with ProductCatalogAssociate Store with RegisterAssociate Register with ProductCatalog

The communication diagram (which would essentially drive the model for the main() function) is shown on the next slide

38

:Store :Register

pc:ProductCatalog

create 2: create(pc)

1: create

1.2: loadProdSpecs()

descriptions:Map<ProductDescription>

1.1: create

1.2.2*: put(id, pd)

1.2.1*: create(id, price, description)

pd:ProductDescriptionthe * in sequence number indicates the

message occurs in a repeating section

pass a reference to the ProductCatalog to the Register, so that it has permanent visibility to it

by Creatorcreate an empty collection object

39

Takeaways from Chapter 18 Understand the Design Model the POS case study

Understand how the GRASP principles were used to create this design

40

Next …Gang of Four Patterns – Chapter 26