Professional Documents
Culture Documents
III Unit Final OOSE
III Unit Final OOSE
It has also been called the Delegation Event Model (in Java) because the pub-
lisher delegates handling of events to "listeners" (subscribers; see Figure 23.25).
Sale
propertyListeners
javax.swing.JFrame
*
... «interface»
setTitle() PropertyListener
setVisible()
... onPropertyEvent( source, name, value )
377
23 - DESIGNING USE-CASE REALIZATIONS WITH GoF DESIGN PATTERNS
{
for each AlarmListener al in alarmListeners
al.onAlarmEvent( this, time );
} {
alarmListeners.add( lis );
}
AlarmClock
setTime( newTime ) {
... time = newTime;
if ( time == alarmTime )
publishAlarmEvent( time );
}
alarmListeners
javax.swing.JFrame
*
... «interface»
setTitle() AlarmListener
setVisible()
... onAlarmEvent( source, time )
{ {
{
display notification dialog check that all required processes
beep
box are executing normally
}
} }
378
FAILOVER TO LOCAL SERVICES WITH A PROXY (GoF)
Proxy
Context / Problem
Direct access to a real subject object is not desired or possible. What to do?
Solution
Add a level of indirection with a surrogate proxy object that implements the
same interface as the subject object, and is responsibility for controlling or
enhancing access to it.
Client 1 «interface»
1 ISubjectInterface
subject : ISubjectInterface
1 foo()
doBar()
{ subject actually 1
... whatever references an
subject.foo() instance of Proxy, Proxy
... whatever not RealSubject RealSubject
} realSubject : ISubjectInterface
foo()
foo()
{
... pre-processing
realSubject.foo() "realSubject" will actually reference an
... post-processing instance of RealSubject
}
Applied to the NextGen case study for external accounting service access, a
redirection proxy is used as follows:
1. Send a postSale message to the redirection proxy, treating it as though
it
was the actual external accounting service.
2. If the redirection proxy fails to make contact with the external service
(via
its adapter), then it redirects the postSale message to a local service,
which
locally stores the sales for forwarding to the accounting service, when it
is active.
521
33 - DESIGNING MORE USE-CASE REALIZATIONS WITH OBJECTS AND PATTERNS
"accounting" actually
{
references an
... payment work
1
instance of
Accounting- if ( payment completed )
RedirectionProxy completeSaleHandling()
}
Register
«interface»
IAccountingAdapter
accounting : IAccountingAdapter 1 1
postReceivable( ReceivableEntry )
+ makePayment()
postSale( Sale )
2 ...
- completeSaleHandling()
{
... 2
accounting.postSale( currentSale 1
) AccountingRedirectionProxy
... SAPAccountingAdapter
} externalAccounting : IAccountingAdapter
localAccounting : IAccountingAdapter
3
{ postReceivable(ReceivableEntry
externalAccounting.postSale(sale) postReceivable( ReceivableEntry )
postSale( Sale ) )
... postSale( Sale )
if ( externalAccounting fails ) ...
localAccounting.postSale(sale)
}
LocalAccounting
{ 4 postReceivable( ReceivableEntry )
save the sale in a local file (to be
forwarded to external accounting postSale( Sale )
...
later)
}
UML notation:
• To avoid creating an interaction diagram to show the dynamic behavior,
observe how this static diagram uses numbering to convey the sequence of
interaction. An interaction diagram is usually preferred, but this style is
presented to illustrate an alternative style.
• Observe the public and private ( +, - ) visibility markers beside Register
methods. If absent, they are unspecified, rather than defaulting to public or
private. However, by common convention, unspecified visibility is inter
preted by most readers (and code generating CASE tools) as meaning pri
vate attributes and public methods. However, in this diagram, I especially
want to convey the fact that makePayment is public, and by contrast,
completeSaleHandling is private. Visual noise and information overload are
522
34 - DESIGNING A PERSISTENCE FRAMEWORK WITH PATTERNS
For example:
1. Suppose the database has a referential integrity constraint such that when
a record is updated in TableA that contains a foreign key to a record in
TableB, the database requires that the record in TableB already exists.
2. Suppose a transaction contains an INSERT task to add the TableB record,
and an UPDATE task to update the TableA record. If the UPDATE executes
before the INSERT, a referential integrity error is raised.
Ordering the database tasks can help. Some ordering issues are schema-specific, but a general
strategy is to first do inserts, then updates, and then deletes.
Mind that the order in which tasks are added to a transaction by an application may not reflect
their best execution order. The tasks need to be sorted just before their execution.
This leads to another GoF pattern: Command.
Command
Context / Problem
How to handle requests or tasks that need functions such as sorting (prioritizing), queueing,
delaying, logging, or undoing?
Solution
Make each task a class that implements a common interface.
This is a simple pattern with many useful applications; actions become objects, and thus can be
sorted, logged, queued, and so forth. For example, in the PFW, Figure 34.15 shows Command (or
task) classes for the database operations.
There is much more to completing a transaction solution, but the key idea of this section is to
represent each task or action in the transaction as an object with a polymorphic execute method;
this opens up a world of flexibility by treating the request as an object itself.
The quintessential example of Command is for GUI actions, such as cut and paste. For example,
the CutCommand's execute method does a cut, and its undo method reverses the cut. The
CutCommand will also retain the data necessary to perform the undo. All the GUI commands
can be kept in a history stack, so that they can be popped in turn, and each undone.
Another common use of Command is for server-side request handling. When a server object receives
a (remote) message, it creates a Command object for that request, and hands it off to a
CommandProcesser [BMRSS96], which can queue, log, prioritize, and execute the commands.
558
LAZY MATERIALIZATION WITH A VIRTUAL PROXY
{
sort()
for each ICommand cmd
cmd.execute()
}
Transaction undo is a no-op for
this example, but a
commands : List
«interface» more complex
1 1..* solution adds a
commit() ICommand
addDelete(obj:PersistentObject) polymorphic undo
execute( ) to each subclass
addInsert( obj:PersistentObject)
undo() which uniquely
addUpdate( obj:PersistentObject)
sort() knows how to undo
... an operation
559
23 - DESIGNING USE-CASE REALIZATIONS WITH GoF DESIGN PATTERNS
Strategy
Context / Problem
How to design for varying, but related, algorithms or policies? How to design for
the ability to change these algorithms or policies?
Solution
Define each algorithm/policy/strategy in a separate class, with a common
interface.
Since the behavior of pricing varies by the strategy (or algorithm), we create
multiple SalePricingStrategy classes, each with a polymorphic getTotal method
(see Figure 23.8). Each getTotal method takes the Sale object as a parameter, so
that the pricing strategy object can find the pre-discount price from the Sale,
and then apply the discounting rule. The implementation of each getTotal
method will be different: PercentDiscountPricingStrategy will discount by a per-
centage, and so on.
«interface»
ISalePricingStrategy
{ {
return s.getPreDiscountTotal() * percentage pdt := s.getPreDiscountTotal()
} if ( pdt < threshold )
return pdt
else
return pdt - discount
}
ISalePricingStrategy
:SalesLineItem :PercentDiscount
s : Sale :SalesLineItem
PricingStrategy
t := getTotal()
* : st := getSubtotal() { t = pdt * percentage }
t := getTotal( s )
Observe that the context object (Sale) needs attribute visibility to its strategy.
This is reflected in the BCD in Figure 23.10.
355
26.9. Facade (GoF)
Another requirement chosen for this iteration is pluggable business rules. That is, at predictable
points in the scenarios, such as when makeNewSale or enterItem occurs in the Process Sale use
case, or when a cashier starts cashing in, different customers who wish to purchase the NextGen
POS would like to customize its behavior slightly.
To be more precise, assume that rules are desired that can invalidate an action. For example:
Suppose when a new sale is created, it is possible to identify that it will be paid by a gift
certificate (this is possible and common). Then, a store may have a rule to only allow one
item to be purchased if a gift certificate is used. Consequently, subsequent enterItem
operations, after the first, should be invalidated.
If the sale is paid by a gift certificate, invalidate all payment types of change due back to the
customer except for another gift certificate. For example, if the cashier requested change in
the form of cash, or as a credit to the customer's store account, invalidate those requests.
Suppose when a new sale is created, it is possible to identify that it is for a charitable
donation (from the store to the charity). A store may also have a rule to only allow item
entries less than $250 each, and also to only add items to the sale if the currently logged in
"cashier" is a manager.
In terms of requirements analysis, the specific scenario points across all use cases (enterItem,
chooseCashChange, ...) must be identified. For this exploration, only the enterItem point will be
considered, but the same solution applies equally to all points.
Suppose that the software architect wants a design that has low impact on the existing software
components. That is, she or he wants to design for a separation of concerns, and factor out this
rule handling into a separate concern. Furthermore, suppose that the architect is unsure of the
best implementation for this pluggable rule handling, and may want to experiment with different
solutions for representing, loading, and evaluating the rules. For example, rules can be
implemented with the Strategy pattern, or with free open-source rule interpreters that read and
interpret a set of IF-THEN rules, or with commercial, purchased rule interpreters, among other
solutions.
Name: Facade
Problem: A common, unified interface to a disparate set of implementations or
interfacessuch as within a subsystemis required. There may be undesirable
coupling to many things in the subsystem, or the implementation of the
subsystem may change. What to do?
Solution: Define a single point of contact to the subsystema facade object that wraps
(advice) the subsystem. This facade object presents a single unified interface and is
responsible for collaborating with the subsystem components.
A Facade is a "front-end" object that is the single point of entry for the services of a subsystem[2]
; the implementation and other components of the subsystem are private and can't be seen by
external components. Facade provides Protected Variations from changes in the implementation
of a subsystem.
[2]
"Subsystem" is here used in an informal sense to indicate a separate grouping of related components, not exactly as
defined in the UML.
For example, we will define a "rule engine" subsystem, whose specific implementation is not yet
known.[3] It will be responsible for evaluating a set of rules against an operation (by some hidden
implementation), and then indicating if any of the rules invalidated the operation.
[3]
There are several free open source and commercial rule engines. For example, Jess, a free-for-academic-use rule engine
available at http://herzberg.ca.sandia.gov/jess/.
The facade object to this subsystem will be called POSRuleEngineFacade. See Figure 26.20. The
designer decides to place calls to this facade near the start of the methods that have been defined
as the points for pluggable rules, as in this example:
lineItems.add( sli );
}
// ...
} // end of class
With this design, the complexity and implementation of how rules will be represented and
evaluated are hidden in the "rules engine" subsystem, accessed via the POSRuleEngineFacade
facade. Observe that the subsystem hidden by the facade object could contain dozens or
hundreds of classes of objects, or even a non-object-oriented solution, yet as a client to the
subsystem, we see only its one public access point.
And a separation of concerns has been achieved to some degreeall the rule-handling concerns
have been delegated to another subsystem.
Summary
The Facade pattern is simple and widely used. It hides a subsystem behind an object.
Related Patterns
Facades are usually accessed via the Singleton pattern. They provide Protected Variations from
the implementation of a subsystem, by adding an Indirection object to help support Low Coupling.
External objects are coupled to one point in a subsystem: the facade object.
As described in the Adapter pattern, an adapter object may be used to wrap access to external
systems with varying interfaces. This is a kind of facade, but the emphasis is to provide
adaptation to varying interfaces, and thus it is more specifically called an adapter.
There is a distinction between pure UI layer responsibilities, that encompass creating
the content and pages for display, vs. what is sometimes called the application control
layerthe layer of components that is responsible for deciding the flow of control, and
directing the presentation layer to display something. In common use, web
presentation frameworks usually imply the inclusion of application control
responsibilities, which is also true of Struts, as it requires developers to create
subclasses of the Struts Action class that are responsible for flow control decisions.
Architectural Patterns
The specific MVC roles mapped to Struts components is illustrated in the UML class
diagram in Figure 2.
Figure 2. MVC roles in Struts.
Related Patterns
The ActionServlet acts as a Facade onto the presentation layer. And although not a
classic Mediator that receives and mediates messaging between other decoupled
objects, it is similar, because an Action object returns an ActionForward object to the
ActionServlet, which is used to direct the next step.
The Struts ActionServlet and Action design also illustrates the Command Processor
pattern, a variant of the GoF Command design pattern. The ActionServlet plays the
role of Command Processor, receiving requests and mapping them to Action
(Command) objects that execute requests.
Struts demonstrates the Front Controller and Business Delegate patterns. The
ActionServlet is the Front Controller, or initial point of contact for handling requests.
The Action objects are Business Delegates-abstractions that delegate to the
"business" or domain layer of services.
The Action objects also play the role of Adapters, adapting the framework calls to the
interface of the domain layer objects.