1937 Sletten D 1 - pietschy.com · Command Pattern • A Design Pattern to allow the...
Transcript of 1937 Sletten D 1 - pietschy.com · Command Pattern • A Design Pattern to allow the...
Session 1937
Beyond Actions
Brian SlettenSystem ArchitectParabon Computation, Inc.
A Semantically Rich Command Pattern for the Java™ Foundation Classes (JFC/Swing) API
Session 19372
Overall Presentation Goal
Learn a low-risk way to take advantage of a richer Command pattern in applications using the Java™ Foundation Classes (JFC/Swing) API
Session 19373
Learning Objectives
• As a result of this presentation, you will understand:– The limitations of conventional GUI
development– The limitations of the Action Interface– The Command Design Pattern– How to fold this into your code gradually
and with minimal risk– The basics of Aspect-Oriented Programming
Session 19374
Speaker’s Qualifications
• Brian Sletten is a System Architect at Parabon Computation, Inc.
• Has a background in user interface and visualization frameworks
• Has used the Command Pattern for eight years with C/C++, Java™ technology and X/Motif
• Former OOAD-certified instructor
Session 19375
Presentation Agenda
• Review: How GUIs Are Built
• Action Interface
• Review: Design Patterns
• Command Pattern
• Making it Happen with JFC/Swing technology
• Happy Consequences
Session 19376
Review: How GUIs Are Built
• Components are laid out– Visually– Programmatically
• Event handlers are registered to call code– The “guts” of an application– Not-so-Good-Old-Days: callbacks – Now: EventListener Objects
Session 19377
Sample Event Handler
class MyActionListener implements ActionListener
{public void actionPerformed( ActionEvent ae ) {System.out.println( “You pressed me!” );
}}
JButton pressMe = new JButton( “Press Me” );ActionListener myAL = new MyActionListener();pressMe.addActionListener( myAL );
Session 19378
What is Wrong With This Approach?
• Hard to add additional invokers– JButtons, JMenuItems, etc.
• Difficult to modify invoker/listener binding– Was JButton, now JList
• Listener is often “dumb” code– Often calls other objects to do real work– Almost impossible to undo behavior– Cannot enable/disable behavior, only
components
Session 19379
What is Wrong With This Approach? (Cont.)
• Heterogeneous event system hard to unify
• Anonymous inner classes are convenient but make it worse– Anonymity is real!– No way to refer to that code elsewhere
• AWT/Swing specific– Other UI toolkits exist
• MIDP as part of the J2ME™ platform• SWT at http://www.eclipse.org
Uses its Own Command!!
Session 193710
What About Action Interface?
Action cutAction = new CutAction();JButton cutButton = new JButton( cutAction );cutAction.setEnabled( false );...class CutAction extends AbstractAction {
public CutAction() {super( “Cut” );
}
public void actionPerformed( ActionEvent ae ) {..}
}
Session 193711
Action Interface Benefits
• Step in the right direction– Eliminates a lot of “dumb code”
• Supports multiple invokers
• JButtons, JMenuItems, etc. handle– Glue code– Shared instances
• Enabledness support– Disable the Action, disable the components
Session 193712
Action Interface Limitations
• Only supports ActionListener!– Did we suddenly forget about
all of the other events and components in the JFC API?
• Needs more abstraction
• No state management
• No support for Undo– Other than UndoManager
Session 193713
Design Patterns
• Solutions to common design problems in a particular context
• An attempt to reuse design, not just code
• Does not eliminate design effort, makes it– Simpler– Cleaner– More robust
Session 193714
How to Get Started with Patterns
• Read Design Patterns [GOF95]
• Look at other examples online
• Pick one that seems appropriate and try it
• Keep in mind:– Use only where appropriate– Don’t force it
Session 193715
Command Pattern
• A Design Pattern to allow the parameterization of a request to an object without special knowledge of the operation requested or the caller’s identity
• Eh?
• Key Points
– Parameterized request to an Object
– Request is an Object
– Loose coupling between caller and receiver
• JButton is unaware of ultimate action or receiver
Session 193716
Command Pattern: Parameterized
• Command maintains its own state or invokes methods on “Receiver” objects– Specific to concrete instance– Ways to parameterize commands
OpenDocumentCommand odc = new OpenDocumentCommand( new Document() );
odc.execute(); // executes on document receiver
OpenWindowCommand owc = CommandFactory.getCommand( “Open Window” );
owc.setValue( w );owc.execute(); // executes on Window receiver
or
Session 193717
Command Pattern : Loose Coupling
• Command objects do not care who invokes them– Component– Other Command– Macro playback script
Button Invoker
Session 193718
Command Pattern :Loose Coupling (Cont.)
Macro Playback Invoker
Session 193719
Command Pattern: Class Diagram
Command “Receiver”
JButton, JList, other components
Concrete Commands
Session 193720
Question
Is the ActionListener an example of the Command Pattern?
Session 193721
XLoose Coupling
√Request is an Object
XParameterized
Answer: No
Session 193722
ActionListener is an Observer Pattern
• Concrete subjects notify concrete observers at an abstract level without coupling
• Also seen in Model-View-Controller (MVC)
JButtonActionListener
Watches
Session 193723
Making it Happen With JFC/Swing Technology
• Goals
• Basic Design
• Helper Classes
• Introduction: Aspect-Oriented Programming
• Using AOP for Commands
Session 193724
Goals
• Low Buy-In Cost
• Basics are basic
• Mechanism, Not Policy– Extensible– Flexible
Session 193725
Basic Design
• Enabledness– setEnabled( boolean value )– boolean getEnabled()
• Dependencies– addDependency(Command cmd )
• Indication of Undo support– canUndo()
• State management– pushState(CommandState state)– CommandState peekState()– CommandState popState()
Session 193726
Command Responsibilities
• Must be named
• Provide an execute() body
• To support undo() should manage its own state– Indicates capability with canUndo()– pushState(), peekState(), popState()
are helpful, but not required
Session 193727
Command Features
• Support PropertyChangeListeners– Observer Pattern!
• Enabledness support– Disabled Commands cannot be executed– Fires propertyChangeEvent
• Supports dependent Commands
Session 193728
Command Features (Cont.)
• Value semantics are available if they are helpful to the Command– void setValue( Object value )– Object getValue()
• Guideline: – Document the Command’s value
expectations and do not abuse lack of type-safety!
Session 193729
CommandFactory
• Organizing point for Commands
• Static methods to add/get Commandsby name
Session 193730
CommandGlue
• Helper class to handle hooking the Commands to components based on type
• Default glue code per component– Marginally subjective– Configurable via file
• Simple for basic mappings
Session 193731
CommandGlue (Cont.)
• Client code can request Command firing for non-default event for flexibility
• Invoker must support the appropriate interface
√√
FocusListener
√XJList
X√JButton
ListSelectionListenerActionListener
Session 193732
Simple App
Session 193733
Introduction: Aspect-Oriented Programming
• A new approach to software development– Works with OOP, does not replace OOP
• OOP organizes classes on relational boundaries– Mostly up vertical hierarchies
• Problem arises when desired behavior touches lots of classes
Session 193734
OOP Inheritance is Good For…
Behavior along verticalrelationships
Session 193735
OOP Inheritance is Not As Good For…
Behavior that crosses horizontal boundaries
Session 193736
Cross-Cutting Concerns
• Behavior that applies across horizontal layers– Logging/Tracing– Thread synchronization– Security
• Behavior needs to be pushed up the hierarchy– Base classes become fat and hard to change!
Session 193737
Modularize Cross-Cutting Concerns
• AOP’s goal: Modularize cross-hierarchy behavior– Easier to maintain– Easier to extend– Compile it in, compile it out
Session 193738
AspectJ and Pointcuts
• AspectJ is an AOP tool for the Java™ platform
• Allows you to define pointcuts– Places in the code during an execution– A little bit like a debugging breakpoint
• “Advice” is the term applied to code that gets run at a breakpoint
• Specify pointcuts with patterns
Session 193739
Pointcut Example
aspect FooSet {
// specifies any call to a method that begins// with the word “set” in class Foo
pointcut setPointCut() :call( public void Foo.set*(*) );
before() : setPointCut() {System.out.println( “You’re about to set!”
);}after() : setPointCut() {
System.out.println( “You just set!” );}
}
Session 193740
More AspectJ
• Aspects and relevant classes get compiled like classes using the ajc compiler
• The magic happens during “compile-time” weaving of pointcut advice
• For more details: – http://www.aspectj.org
Session 193741
Using AOP for Commands
• We want to use AOP where it will help, not just because it is cool– Command Glue
• hook Commands to components– Undo/Redo
• state management before/after execute()
• AOP isn’t necessary, but it is elegant
Session 193742
Gluing Commands with Aspects
pointcut glue( JComponent jc, Object key, Object value ) :
call( void putClientProperty( *, * ) ) &&args( key, value ) && target( jc );
// allows advice to be specified for:JButton clearButton = new JButton();clearButton.putClientProperty(
Command.COMMAND_NAME_PROPERTY, “clear_cmd” );
The “glue” pointcut occurs here
Session 193743
Gluing Commands with Aspects (Cont.)
after( JComponent jc, Object key, Object value ) : glue( jc, key, value ) {if(key.equals(Command.COMMAND_NAME_PROPERTY)) {
CommandGlue.setCommand( jc, ( String ) value );
}}
This after advice for the “glue” pointcut connects JComponents to named Commands via default EventListener
Session 193744
Undo/Redo
• Different policies for this behavior
• Defining the policy at Command level will make it harder to change
• It’s still difficult to apply to all Commands (especially ones we don’t write!)
Session 193745
Undo Pointcut
pointcut commandExecuted( Command cmd ) : call( void Command.execute() ) &&target( cmd ) && !target( UndoCommand ) &&!target( RedoCommand );
Target is a Command, but not the UndoCommand or RedoCommand
Whenever execute is called on a Command object (and descendants!)
Session 193746
Undo Advice
after( Command cmd ) : commandExecuted( cmd ) {String undoName =
UndoCommand.DEFAULT_NAME; UndoCommand undoCmd = ( UndoCommand )
CommandFactory.getCommand( undoName );
undoCmd.setValue( cmd );}
UndoCommand’s value is interpreted as last executed Command
Get the UndoCommand from CommandFactory
Session 193747
Happy Consequences
• Other features almost fall out of the Command Pattern – Application Auditing– Macro Record/Playback– Role-based Capabilities
Session 193748
Application Auditing
• Auditing is simply half of Macro recording
• Establish recording mechanics– File system, RMI server, encryption, etc.
• Create after() advice for Command execution– Capture Command name and timestamp
Session 193749
Macro Record/Playback
• Another cross-cutting concern that would complicate the Command base class and might not be used
• Using aspects allows us to localize this behavior– Introduce capabilities over time– Apply as needed– Change behavior easily
Session 193750
Role-based Capabilities
• Java™ Authentication and Authorization Service (JAAS) API associates Identities with credentials
• Consider combinations of Commands, aspects and Identities– Map Command names to credentials
• CHANGE_CONFIG requires Role(Operator)• VIEW_CONFIG requires Role(Any)
– Enable capabilities at login time• Perhaps a LoginContext.login() pointcut
– Check permissions in around() advice on execute() pointcut
Session 193751
Come Together
• The JFC/Swing API is a rich toolkit!• Much can be done to improve Java
technology UI apps– Commands– Application frameworks– Reusable components– New capabilities
• Check out: – http://www.swingcommunity.org
Session 193752
Summary
• Command Design Pattern opens many possibilities for JFC/Swing API-based apps
• Easy to incorporate gradually– No big buy-in required
• AOP is an implementation decision here– Offers elegant expression of ideas– Modularizes cross-cutting concerns– Keeps the base classes lighter– Not strictly necessary
Session 193753
If You Only Remember One Thing…
Mixing Java™ Foundation Classes (JFC/Swing) technology with creative design approaches can unleash exciting new features
Session 193754
Suggested Reading
[GOF95] Design Patterns, Erich Gamma, Richard Helm, Ralph Johnson, 1995. Addison-Wesley
[Grosso01] For a non-UI use of Command Pattern: http://www.onjava.com/pub/a/onjava/2001/10/17/rmi.html
[Metsker02] The Design Patterns Java™ Workbook, Steven J. Metsker, 2002. Addison-Wesley [Published this spring]
[Young92] Object-Oriented Programming w/C++ and OSF/Motif, Douglas A. Young, 1992. Prentice Hall
More references
Session 1937
Session 1937