Elemental Design Patterns

advertisement
Jason Smith
The Software Revolution, Inc.
based on UNC PhD work, and
“Elemental Design Patterns”, Addison-Wesley, 2012



Used to extend behavior dynamically, at run
time
Like an internal plug-in system as found in a
web browser
Alternative to using inheritance to provide all
possible combinations of behaviors
Zimmer, 1995



Allows a single object interface to represent
multiple concrete implementations
Client requests a method to be invoked via
the objectifier interface
Client cannot know which of the concrete
method bodies will execute and provide the
service
Woolf, 1998




Chains two objects with related types
Object recursion uses Objectifier as the
backbone of its form…
Adds a link between one of the concrete
implementations and the interface
Uses the link to invoke the same method -to “recurse” in a sense, but on a different
(related) object

So Decorator can be
described in terms of
composing smaller
pieces
Are these pieces as
small as they can be?

Perhaps there is
more “downward” to
go


Where is the bottom
of this abstraction
pile?

So Decorator can be
described in terms of
composing smaller
pieces
Are these pieces as
small as they can be?

Perhaps there is
more “downward” to
go


Where is the bottom
of this abstraction
pile?

So Decorator can be
described in terms of
composing smaller
pieces
Are these pieces as
small as they can be?

Perhaps there is
more “downward” to
go


Where is the bottom
of this abstraction
pile?
EDP

So Decorator can be
described in terms of
composing smaller
pieces
Are these pieces as
small as they can be?

Perhaps there is
more “downward” to
go


Where is the bottom
of this abstraction
pile?
decorator
object
recursion
objectifier
EDP
Elemental design patterns
Design Pattern
A common solution to a common problem within a
particular context
Solution
Context
Problem
•structure
•intent
•applicability
•implementation
•motivation
•consequences
•sample code
•known uses
•related patterns
Hard to fit:
participants, collaborations

Participants, Collaborations are parts and

Relationships form the core of design




relationships
Design of a car is more than a piles of pieces…
engine, tires, transmission, seats
Design shows how the parts relate… connect,
interact, work of one affects function of another
Parts list gives components
Relationships tell how parts function in concert
to win over the entropy of the pile




What is smallest relationship we can define?
A single concept connection between two
things
Look for such among the entities in OO
programming
Means we have to decide…
what are the conceptual entities
in OO programs?



Goal: detect elemental relationships
automatically, if we can
Goal: compose elemental patterns to get
higher patterns (automatically, if we can)
Higher pattern means more complex,
harder to find patterns

Different relationships, different purposes

Scoping relationships give context

Scope is how an element is made unique
among all other elements in the system
class Menu in package GUI_Elements is not the same
thing as
class Menu in package Restaurant_Items

Scope: an enclosing something that has a
name, in which you define something new

Class: scope for methods and fields it
defines

Package/namespace: scope for all in it

Method/function: scope for local variables

Access an element: specify the scopes from
outer level in
◦ Implicit notation: No scope for locals in a
method, or another method in same class
◦ Differing notation:
GUI_Element::Menu vs. aMenu.anItem

We now have scope relationships… what else can
we form relationships between?

Classes, their fields and methods…. not much else

What about objects? Different from classes?

Classes do two things
◦ Type information… member methods and fields that will
exists separately in each object created
◦ Global shared fields… “static” class methods and fields

Class is really a type with an object (for global)
Fields, Methods, Objects, Types
OO entities we characterize relationships among
Object
Method
Field
Type
Object
Defines
Defines
Defines
Defines or
Is of type
Method
N/A
Defines or
Defines or
Method call Field use
Defines or
Returns of
type
Field
N/A
State
change
Cohesion
Is of type
Type
Defines
Defines
Defines
Defines or
subtyping
Fields, Methods, Objects, Types
Defines is a scope relationship
Object
Method
Field
Type
Object
Defines
Defines
Defines
Defines or
Is of type
Method
N/A
Defines or
Defines or
Method call Field use
Defines or
Returns of
type
Field
N/A
State
change
Cohesion
Is of type
Type
Defines
Defines
Defines
Defines or
subtyping
Object
Method
Field
Object
Method
Field
Type
Type
Is of type
Method call Field use
Returns of
type
State
change
Is of type
Cohesion
subtyping
o . f( ) calls p . g( )
enclosing
object
Calling
method
enclosing
object
Called
method
A
B
b: B
g()
h()
f()
b.g()
class A {
B b;
f ( ) { b.g(); }
}
class B {
g ( ) { }
h ( ) { }
}
main ( ) {
A a;
a.f();
}
object
similarity
similar
dissimilar
Conglomeration
Recursion
Delegation
Redirection
dissimilar
similar
method
similarity

s-calculus
◦ Abadi and Cardelli, “A Theory of Objects”, 1998
◦ Computation model for OO programs
◦ Object form of l-calculus

r-calculus
◦ Modification and extension for patterns
◦ Operators for reliances
◦ J. Smith, 2004





Focus on OO programming concepts, not OO
language constructs
a.f() calls b.g(), then b.g() calls c.h()
We can see that a.f() does not call c.h() (a
structural relationship)
However a.f() relies on c.h() to execute
correctly in order for f to complete its work
So there is a reliance between a.f() and c.h()
(conceptual, not structural)


Zimmer, W. Relationships between design patterns. In J.O.
Coplien and D.C. Schmidt, eds., Pattern Languages of
Program Design. Addison-Wesley, Voston, 1995, pp. 345364.
Woolf, B. The object recursion pattern. In N. Harrison, B.
Foote, and H. Rohnert, eds., Pattern Languages of Program
Design 4. Addison-Wesley, Boston, 1998, pp. 41-52.
•
Provide tools to software engineers to aid in
the efficient comprehension of existing code
bases (maintenance, new design with re-use)
•
Provide support for development of new code
that adheres to best-practices architecture
•
Create metrics to compare relative
comprehensibility and relative quality of
system designs for analysis prior to
implementation
•
Why find patterns?
“Common (agreed good) solutions to common problems”
•
Abstractions of lessons learned
•
GoF 1995
•
Culling code down to the language-independent
ideas, not implementation specifics …
•
Community agreement on what gains “pattern” status
•
Common vocabulary for software engineers to
discuss and compare design issues, best practices,
architecture and organization
•
Assembly mnemonics
•
Procedural programming -- locality of code
•
Object-oriented programming -- encapsulation of
data with code
•
Idioms
best language practices
•
Design patterns
best design practices, language independent
“Composite”
“Composite”
// Composite pattern -- Structural example
using System;
using System.Text;
using System.Collections;
// "Component"
abstract class Component
{
// Fields
protected string name;
// Constructors
public Component( string name )
{ this.name = name; }
// Methods
abstract public void Add(Component c);
abstract public void Remove( Component c );
abstract public void Display( int depth );
}
// "Composite"
Class Composite : Component
{
// Fields
private ArrayList children = new ArrayList();
// Constructors
public Composite( string name ) : base( name ) {}
// Methods
public override void Add( Component component )
{ children.Add( component ); }
public override void Remove( Component component )
{ children.Remove( component );}
public override void Display( int depth )
{ Console.WriteLine( new String( '-', depth ) + name );
// Display each of the node's children
foreach( Component component in children )
component.Display( depth + 2 );
}
}
// "Leaf"
class Leaf : Component
{ // Constructors
public Leaf( string name ) : base( name ) {}
// Methods
public override void Add( Component c )
{ Console.WriteLine("Cannot add to a leaf"); }
public override void Remove( Component c )
{ Console.WriteLine("Cannot remove from a leaf"); }
public override void Display( int depth )
{ Console.WriteLine( new String( '-', depth ) + name ); }
}
public class Client
{
public static void Main( string[] args ) {
// Create a tree structure
Composite root = new Composite( "root" );
root.Add( new Leaf( "Leaf A" ));
root.Add( new Leaf( "Leaf B" ));
Composite comp = new Composite( "Composite X" );
comp.Add( new Leaf( "Leaf XA" ) );
comp.Add( new Leaf( "Leaf XB" ) );
root.Add( comp );
root.Add( new Leaf( "Leaf C" ));
// Add and remove a leaf
Leaf l = new Leaf( "Leaf D" );
root.Add( l );
root.Remove( l );
// Recursively display nodes
root.Display( 1 );
}
}
// Purpose.
Composite
#include <string.h>
enum NodeType { FileT, DirT };
int g_indent = 0;
class File {
public:
File( char* n ) { type_ = FileT;
strcpy( name_, n ); }
NodeType getType() { return type_; }
void ls() {
for (int i=0; i < g_indent; i++)
cout << ' ';
cout << name_ << endl; }
private:
NodeType type_;
char
name_[20];
};
//
//
//
//
//
//
//
//
Strategy. Use recursive composition
to create a heterogeneous aggregate
that can be treated homogeneously.
Benefit. No more type checking and
type casting (coupling between Dir
and File is gone, Dir is only
coupled to abstract base class)
class AbsFile {
public:
virtual void ls() = 0;
protected:
char
name_[20];
static int indent_;
};
int AbsFile::indent_ = 0;
class File: public AbsFile {
public:
class Dir {
File( char* n ) {
public:
strcpy( name_, n ); }
Dir( char* n ) { type_ = DirT;
void ls() {
strcpy( name_, n ); total_ = 0; }
for (int i=0; i < indent_; i++)
NodeType getType() { return type_; }
cout << ' ';
void add( File* f ) {
cout << name_ << endl; }
files_[total_++] = f;
};
}
void ls() {
class Dir : public AbsFile {
for (int i=0; i < g_indent; i++) public:
cout << ' ';
Dir( char* n ) {
cout << name_ << ":" << endl;
strcpy( name_, n ); total_ = 0; }
g_indent += 3;
void add( AbsFile* f ) {
(defgeneric add-dependent (dm dependent &optional recursivep)
;; see below for the optional args
(:documentation
"Add DEPENDENT as a dependent of DM. Return DM"))
(defgeneric delete-dependent (dm dependent &optional recursivep)
(:documentation
"Remove DEPENDENT from DM. Return DM"))
;;; No DELETE-DEPENDENT-IF
(defgeneric map-dependents (f dm)
(:documentation
"Map F over the dependents of DM.
Return DM"))
;;; No cursors.
(defgeneric make-collection-for-dependent-mixin (dm))
A solution must be
language
independent
(defclass dependent-mixin ()
;; something that has dependents. We expose the DEPENDENTS slot.
((dependents :reader dependents-of)))
(defmethod make-collection-for-dependent-mixin ((dm dependent-mixin))
(make-instance 'simple-childed-mixin))
(defmethod initialize-instance :after ((dm dependent-mixin) &key)
(setf (slot-value dm 'dependents)
(make-collection-for-dependent-mixin dm)))
(defmethod add-dependent ((dm dependent-mixin) dependee
&optional recursivep)
(declare (ignorable recursivep))
All non-trivial designs
involve many
cross-mixed
patterns
Same class might
be a component
in 4 or 5 patterns
•
GoF patterns are too large to formalize flexibly
•
“Mini-patterns” have been tried but still at too large a
graularity
•
Cannot handle implementation variances, due to
static definitions of patterns… no inference
capabilities
•
GoF patterns are too large to formalize flexibly
•
Divide and conquer… define “bricks” and “wall
construction procedures”
•
Call them Elemental Design Patterns ( EDP )
• Idea is for EDPs to be easy to find in code
• Use resolution theorem prover to do the “wall
assembly”
• Add to the assembly methods rules that allow flexible
variations on basic definitions
Relationships are the key
Method calls: relationships between functions
Field access: relationships between objects
Inheritance: relationships between types
Objects, Types, Methods, Fields…
What else is there in OO? That’s it…
Source code
gcc2poml
gcc
gcc parse tree
object XML
poml2otter
EDP catalog
Rho calculus
compos rules
Source-codespecific otter
clauses
Found
patterns
report
python
Otter theorem prover
Otter proofs
Object element EDPs
CreateObj
AbsInterface
Retrieve
Type Relation EDPs
Inheritance
Method Invocation EDPs
Recursion RedirectedRecursion
Redirect
RedirectInFamily
RedirectInLimitedFamily
Delegate DelegateInFamily DelegateInLimitedFamily
Conglomeration
DelegatedConglomeration
ExtendMethod
RevertMethod
•
Successful in composing the EDPs to define 22 of
the 23 GoF patterns
•
Can produce many other described patterns as well
from the literature
and mini’s… Objectifier, ObjRecursion
•
23rd GoF pattern is Iterator …
Really a language construct, not a pattern
Is an operation for a data type
•
•
Begin with s-calculus ( OO analog to l-calculus )
Add ability to encode relationships between
constructs with reliance operators … gives r-calculus
Describe relationships between objects, methods, and fields
Transitive
A<<B, B<<C : A<<C
•
Define EDPs directly in r-calculus
•
Express more complex patterns as compositions and
assemblies of EDPs
•
Encode it all as Otter clauses
Source code
gcc2oml
gcc
gcc parse tree
object XML
oml2otter
EDP catalog
Rho calculus
compos rules
Source-codespecific otter
clauses
Found
patterns
report
python
Otter theorem prover
Otter proofs
•
Flexibility requires capturing variations on a basic
pattern
•
Static definition/specification cannot capture the
many different detailed forms code may take and still
be judged a “pattern instance”
•
Implementation may differ, clutter may be more or
less, extra objects may be imposed, but
the base roles appear,
their relationships stay the same
•
Code trials
•
Problem from Evans and Sutherland
•
C++ standard library analysis for EDPs
•
Working code from previous projects (OvalTine)
•
Hundreds of patterns are named and in use
•
How do we get these into the formal dictionary?
Must a programmer be a r-calculus expert?
•
New patterns can be added via “training”
•
Write a canonical program that contains the
necessary and sufficient code components
comprising the pattern ( and little else )
SPQR tools will extract the facts into r-calculus
Hand tune the definition and test
•
Vary by type… inheritance
•
Get the photo of whiteboard
•
MDL explains patterns existence
•
Why are patterns the way they are?
•
MDL explains it… GoF are minimal in several
measures that make sense for software
complexity
•
Software Architecture
•
Near zero learning curve
•
Adding to existing tool chain, not replacing it
•
Not adding to workload of engineer
•
Analogous to a spelling checker or execution profiler
•
Theorem prover + r-calculus + transitivity (isotopes)
gives searching over infinite design space using finite number
of definitions
•
New way to teach OO concepts and design
Method similarity fixed at “similar”
Method similarity fixed at “dissimilar”
Download