Review of Course/Syllabus

Download Report

Transcript Review of Course/Syllabus

Structural Design Patterns
Yaodong Bi
July 18, 2015
Structural design patterns







Façade
Decorator
Composite
Proxy
Adapter
Bridge
Flyweight
Façade

Design Purpose
– Provide a single and simple interface to a
package of classes

Design Pattern Summary
– Define a single and simple interface for
clients to use the functionality of the
package
Façade - examples

A compiler package
– It normally contains many
classes/subpackages like Scanner, Parser,
etc.
– Most clients only want to compile their
programs, i.e., they don’t care about
functions of individual components in the
package
– Use Façade to provide a simple default
interface to most clients.
Façade - Structure
Client
Use op1(), op2(),
op3(), and op4()
Facade
op1()
op2()
op3()
op4()
ClassA
ClassC
op3_a()
op4_c()
ClassB
op1_b()
op2_b()
Sequence Diagram
Client
op1()
Facade
op1_b()
op3()
op3_a()
op4()
op4_c()
op2()
op2_b()
B:ClassB
A:ClassA
C:ClassC
Façade - Structure
Client
Compiler.compile(“test.c”)
Compiler
compile()
ProgramNodeBuilder
Scanner
CodeGenerator
Parser
Façade – Sample code
Class Scanner {
public Scanner(InputStream sourcecode)
public Token scan() { … }
}
Class Parser {
public parse(Scanner s, ProgramNodeBudiler p) {
…}
}
Class ProgramNodeBuilder {
public ProgramNode newVariable(…) { … }
public ProgramNode newAssignment(…) { … }
public ProgramNode newReturnStmt(…) { … }
}
Class CodeGenerator {
public void visitStatementNode(…) { … }
public void visitExpressionNode(…) { … }
}
Class Compiler {
public void compile(InputStream sc,
OutputStream bytecode) {
Scanner sc = new Scanner(sc);
ProgramNodeBuilder pnb = new
ProgramNodeBuilder();
Parser parser = new Parser();
parser.parse(sc, pnb);
IntelCodeGenerator cg = new
IntelCodeGenerator(bytecode)
ProgramNode nodetree =
pnb.getRootNode();
parsetree.traverse(cg);
}
Façade - Examples
framework
AccountException
CustomerException
Customer
Account
getCustomerName()
getNumAccounts()
getPersonalNote()
getAccount( int )
getAccountNum()
deposit( int )
getBalance()
BankCustomers
BankCustomer
Client
1..n
BankCustomers
doDeposit( int amt, Customer cust, Account acc )
getBankAccount( Customer cust, int accNum )
getBankCustomer( String custName )
BankAccount
Façade - comments

Façade can reduce the degree of
dependency between packages
– Packages are dependent on each other only
through their facades, not individual classes


Use Façade to provide a simple default view
of the package that is enough for most
clients
Façade does not try to encapsulate/hide the
components in the package since there may
be clients who need to access individual
components in the package
Decorator

Design Purpose
– Add responsibilities to an object at
runtime.

Design Pattern Summary
– Provide for a linked list of objects, each
encapsulating responsibility.
Decorator - examples

The word processor example
– A text view may have a border and a
scroll bar and maybe other bells and
whistles attached to it
– How can those bells and whistles be
added to the text view?
– Inheritance?
Decorator – structure
Component
operation()
add(Component)
remove(Component)
getChild()
Client
ConcreteComp
operation()
Decorator
Operation()
void operation()
{
// do actions of the decorator
comp.operation();
// do actions of the decorator
}
comp
Decorator - example
Decorator – structure
VisualComponent
draw()
Client
TextView
draw()
Decorator
draw()
comp
comp.draw()
ScrollDecorator
draw()
scrollTo()
scrollPosition
BorderDescrotor
draw()
drawBorder()
borderWidth
super.draw()
this.drawBorder()
Decorator – examples
Client
:Decorator1
:Decorator2
:ConcreteComp
Decorator - Sequence Diagram
Component
Client
operation()
:Decorator1
:Decorator2
:ConcreteComp
operation()
operation()
operation()
return
return
return
return
Decorator – examples
:Reader
1
:InputStreamReader
System.in:InputStream
: BufferedStreamReader
Decorator – examples
: BufferedStreamReader
:InputStreamReader
System.in:InputStream
Decorator – key concept

allows addition to and removal from
objects at runtime
Decorator – sample code
class VisualComponent {
virtual void Draw();
virtual void Resize();
};
class Decorator : public VisualComponent {
Decorator(VisualComponent*);
void Decorator::Draw () {
_component->Draw();
}
VisualComponent* _component;
};
class BorderDecorator : public Decorator {
BorderDecorator(VisualComponent*, int
borderWidth);
void Draw(){
Decorator::Draw();
DrawBorder(_width);
}
private void DrawBorder(int);
private int _width;
};
Class Window {
void SetContents (VisualComponent*
contents) {
// ...
}
Window* window = new Window();
TextView* textView = new TextView;
window->SetContents(textView);
window->SetContents(
new BorderDecorator(
new ScrollDecorator(textView), 1
)
);
Window.draw();
Composite

Design Purpose
– Represent a Tree of Objects

Design Pattern Summary
– Use a Recursive Form in which the tree
class aggregates and inherits from the
base class for the objects.
Composite - structure
Objects
Classes
Component
1..n
non-leaf node
leaf node
“every
object
involved
is a
Component
object”
NonLeafNode
“non-leaf nodes
have one or more
components”
Composite - structure
Component
Client
add( Component )
Remove(component)
doIt()
1..n
comp
LeafNode
doIt()
NonLeafNode
doIt()
TypeANonLeafNode
doIt()
for all elements e in comp
e.doIt()
TypeBNonLeafNode
doIt()
Composite – A Class Diagram
:Client
N0:NonLeafNode
N1:NonLeafNode
L1:LeafNode
L2:LeafNode
N2:NonLeafNode
L3:LeafNode
Composite – sequence diagram
:Client
doIt()
N0:NonLeafNode
doIt()
N1:NonLeafNode
L1:LeafNode
L2:LeafNode
L3:LeafNode
N2:NonLeafNode
doIt()
doIt()
doIt()
doIt()
Composite – examples
Component
1..n
Composite in java.awt
Container
Window
Canvas
component
…..
Proxy

Design Purpose
– Avoid the unnecessary execution of
expensive functionality in a manner
transparent to clients.

Design Pattern Summary
– Interpose a substitute class which
accesses the expensive functionality only
when required.
Proxy – examples
Client
Instantiate with
Proxy object
RealActiveClass
expensiveMethod()
anotherMethod()
BaseActiveClass
expensiveMethod()
anotherMethod()
Proxy
expensiveMethod()
anotherMethod()
if ( realActiveObject == null )
// not loaded yet
{ realActiveObject = getRealActiveObject();
realActiveObject.expensiveMethod();
}
else { realActiveObject.expensiveMethod(); }
Proxy – sequence diagram
Client
BaseActiveClass
Proxy
RealActiveClass
expensiveMethod()
create() if needed
expensiveMethod()
Proxy – examples
Instantiate with
Proxy object
TexDoc
Graphics
Display()
graphics
Image
image
display()
bitmap
ImageProxy
display()
fileName
if ( image == null ) {
// not loaded yet
image = new Image(fileName);
}
Image.display();
Proxy – Sample code
Class TextDoc {
graphics g;
TextDoc(ImageProxy ip) {
g = ip;
}
void display() {
g.display();
}
}
Class ImageProxy implements Graphics {
FileName fileName;
Image image;
ImageProxy(FileName fn) {
fileName = fn;
}
display() {
if (image == null)
image = new Image(fileName);
image.display();
}
}
Interface Graphics {
display();
}
Class Image Implements Graphics {
Bitmap bitmap;
Image(FileName fn) {
bitmap = readImage(fn);
}
display() {
// draw the bitmap
}
readImage(FileName fn) {
// read from the file(fn)
// create a bitmap
}
}
Adapter

Design Purpose
– Allow an application to use external
functionality in a retargetable manner.

Design Pattern Summary
– Write the application against an abstract
version of the external class; introduce a
subclass that aggregate the external
class.
Adapter - examples

Interact with legacy systems
– When you design a new system which has to
interact with a legacy system, you may not want
to the new system tightly coupled with (or
dependent upon) the legacy system since the
legacy system may be replaced in the future.

Using 3rd party systems
– You may want to be able to easily substitute the
current 3rd party system with another one.
Class Adapter
Object Adapter - Structure
Client
Target
Adaptee
+request()
Adapter
+request()
adaptee.requestedMethod()
+requestedMethod();
adaptee
Adapter – sequence diagram
Client
Target
request(TargetIn):TargetOut
Adapter
request(TargetIn):TargetOut
Adaptee
convert(TargetIn):AdapteeIn
requestedMethod(AdapteeIn):AdapteeOut
Return TargetOut
Return TargetOut
convert(AdapteeOut):TargetOut
Object Adapter – sample code
Interface Target {
public TargetOut request(TargetIn);
}
Class Adaptee {
…
public AdapteeOut
requestedMethod(AdapteeIn)
{
// produce AdapteeOut;
return AdapteeOut;
}
…
}
Class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee ad) {
adaptee = ad;
}
public TargetOut request(TargetIn ti) {
AdapteeIn ai = convert(ti);
AdapteeOut ao =
adaptee.requestedMethod(ai);
return convert(ao);
}
private AdapteeIn convert(TargetIn ti)
{
// convert TargetIn to AdapteeIn
}
private TargetOut convert(AdapteeOut ao)
{
// convert AdapteeOut to TargetOut
}
}
Object Adapter - Example
DrawingTool
Shape
TextView
+boundingBox()
+createManipulator()
TextShape
+getExtent();
text
+boundingBox()
+createManipulator()
text.getExtent()
return new TextManipulator()
Design for Adaption

Pluggable Adapters
– A small set of operations is specified for
adapter & adaptee to implement
– Using Abstract Operations
Client and target are the same entity
 Adapter overrides abstract operations to
delegate operations to adaptee

– Using Delegate Objects

A delegate interface specifies operations the
adapter needs to implement
Using Abstract Operations
Using Delegate Objects
Adapter - comments

An adapter may have more than one adaptee
– There may not be a one-to-one correspondence
between operations of Target and those of
Adaptee
– So it is possible that an operation of Target is
realized with two separate adaptee classes.

The pattern decouples Client from adaptee.
– When a different adaptee is needed, we only need
to change to another adapter and the client does
not need to change at all.
Structural Patterns - Summary





Facade provides an interface to
collections of objects
Decorator adds to objects at runtime
Composite represents trees of objects
Proxy avoids calling expensive
operations unnecessarily
Adapter decouples client from an
existing system