March 2003 91.3913 R. McFadyen 1
Pure Fabrication 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.
Ch 22: GRASP Patterns
Pure Fabrication
Protected Variations (Law of Demeter)
March 2003 91.3913 R. McFadyen 2
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
March 2003 91.3913 R. McFadyen 3
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.
March 2003 91.3913 R. McFadyen 4
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
March 2003 91.3913 R. McFadyen 5
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.
March 2003 91.3913 R. McFadyen 6
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
March 2003 91.3913 R. McFadyen 7
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
March 2003 91.3913 R. McFadyen 8
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
March 2003 91.3913 R. McFadyen 9
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
March 2003 91.3913 R. McFadyen 10
Object Design 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:
March 2003 91.3913 R. McFadyen 11
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
March 2003 91.3913 R. McFadyen 12
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.”
March 2003 91.3913 R. McFadyen 13
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
March 2003 91.3913 R. McFadyen 15
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
March 2003 91.3913 R. McFadyen 16
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
March 2003 91.3913 R. McFadyen 17
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()
March 2003 91.3913 R. McFadyen 18
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()
March 2003 91.3913 R. McFadyen 19
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
March 2003 91.3913 R. McFadyen 20
Example: Applying LoD as system changes
BusRoute BusStopList
BusStopBusList
Bus PersonList
Person
passengers
buses
busStops
waiting
0..*
0..*
0..*
March 2003 91.3913 R. McFadyen 21
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:
March 2003 91.3913 R. McFadyen 22
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
March 2003 91.3913 R. McFadyen 23
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
Top Related