28
02 - Structural Design Patterns – 1 Moshe Fresko Bar-Ilan University חחח"ח2008

02 - Structural Design Patterns – 1 Moshe Fresko Bar-Ilan University תשס"ח 2008

Embed Size (px)

Citation preview

02 - Structural Design Patterns – 1

Moshe Fresko

Bar-Ilan University

תשס"ח

2008

Structural Patterns Structural Patterns are concerned with how classes and objects

are composed to form larger structures. Adapter: Makes an interface to conform to another. So it makes

a uniform abstraction of different interfaces. Composite: Describes how to build class hierarchy made up of

classes for two kinds of objects: primitive and composite. Proxy: Acts as a convenient surrogate or placeholder for another

object Flyweight: Defines a structure for sharing objects Decorator: How to add responsibilities to objects dynamically. Façade: How to make a single object represent an entire

subsystem Bridge: Separates an object's abstraction from its

implementation so that you can vary them independently

Decorator

Moshe Fresko

Bar-Ilan University

2005-2006 - תשס"ו

Design Patterns Course

Decorator Intent: Attach additional responsibilities to an object dynamically.

Decorators provide a flexible alternative to sub-classing for extending functionality.

Motivation: Sometimes we want to add responsibilities to individual objects not to an

entire class. A GUI toolkit should let you add properties like borders or scrolling to any

component An inflexible way of doing it is by inheritance. A more flexible way is to enclose the component in another object that

adds the border. The enclosing object is called a decorator. The decorator conforms the interface of the component it decorates The decorator forwards requests to the component and may perform

additional actions.

Decorator – Motivation

Decorator – Motivation

Decorator – Applicability

Use Decorator To add responsibilities to individual objects

dynamically and transparently. For responsibilities that can be withdrawn. When extension by sub-classing is impractical.

Decorator – Motivation We want to define an abstract Food class (or a Food Interface) to represent any

food that is offered by a Pizza shop. Let’s look at the following design …interface Food { float getPrice() ; String getDescription() ; } class Pizza implements Food { float getPrice() { return 50 ; } String getDescription() { return “Regular Pizza” ; } }class PizzaWithOnion extends Pizza // Adds 5 shekels { float getPrice() { return super.getPrice()+5 ; } String getDescription() { return super.getDescription() + “ with Onion” ; } }

Decorator – Motivationclass PizzaWithCorn extends Pizza { // Adds 7 shekels

…}class PizzaWithOnionAndCorn extends Pizza { // Adds 12 shekels

…}

// Etc.

… // In the program

Food f = new PizzaWithOnionAndCorn() ;

System.out.println(“You bought : “+f.getDescription()) ;System.out.println(“Price in Shekels is : “+f.getPrice()) ;

Decorator – Motivation

Problems:1. Many classes have to be defined… (For all the

combinations)

2. What if Corn’s price will rise from 7 shekels to 8 shekel ?

3. What if we have another addition, let’s say “Tuna Fish” ?

Decorator – Motivation Alternative design with “Decorator” patterninterface Food { float getPrice() ; String getDescription() ; } class Pizza implements Food { float getPrice() { return 50 ; } String getDescription() { return “Regular Pizza” ; } }class Addition implements Food { Food f ; Addition(Food f) { this.f = f ; } float getPrice() { return f.getPrice() ; } String getDescription() { return f.getDescription() ; } }

Decorator – Motivationclass PlusOnion extends Addition

{ PlusOnion(Food f) { super(f) ; } float getPrice() { return super.getPrice() + 5 ; } String getDescription() { return super.getDescription() + “, with Onion”); }

} class PlusCorn extends Addition

{ PlusCorn(Food f) { super(f) ; } float getPrice() { return super.getPrice() + 7 ; } String getDescription() { return super.getDescription() + “, with Corn”); }

}// Etc.

… // In the program

Food f = new PlusOnion(new PlusCorn(new Pizza())) ;…System.out.println(“You bought : “+f.getDescription()) ;System.out.println(“Price in Shekels is : “+f.getPrice()) ;

Decorator – Structure

Decorator - Participants

Component Defines the interface for objects that can have

responsibilities added to them dynamically. ConcreteComponent

Defines an object to which additional responsibilities can be attached.

Decorator Maintains a reference to a Component object and defines

an interface that conforms to Component’s interface. ConcreteDecorator

Adds responsibilities to the component.

Decorator – Consequences

1. More flexibility then static inheritance

2. Avoids feature-laden classes high up in the hierarchy

3. A decorator and its component are not identical

4. Lots of little objects

Decorator – Implementation

1. Interface conformance

2. Omitting the abstract Decorator class

3. Keeping Component class lightweight

4. Changing the skin of an object versus changing the guts (like Strategy).

Decorator Example – Java Streams InputStream

FileInputStream : Reads from a file ByteArrayInputStream : Reads from a byte-array StringBufferInputStream : Reads from a String PipedInputStream : Reads from another output pipe SequenceInputStream : Reads from two or more “InputStreams” sequentially FilterInputStream : As a “DECORATOR” abstract class

DataInputStream : To Read Primitive Data Types. readInt(), readByte() BufferedInputStream : Adds buffering LineNumberInputStream : Counts the number of lines PushbackInputStream : Can push-back a character

OutputStream FileOutputStream ByteArrayOutputStream PipedOutputStream FilterOutputStream

DataOutputStream PrintStream BufferedOutputStream

Decorator Example – Java Streams// As it is defined in Java

public abstract class InputStream { // ... public abstract int read() throws IOException;

public int read(byte b[]) throws IOException { return read(b, 0, b.length); }

public int read(byte b[], int off, int len) throws IOException { // ...

} // ... public void close() throws IOException { } // ...}

Decorator Example – Java Streams// As it is defined in Java

public class FilterInputStream extends InputStream { protected InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } public int read() throws IOException { return in.read(); } public int read(byte b[]) throws IOException { return read(b, 0, b.length); } public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } public void close() throws IOException { in.close(); } // ... }

Decorator Example – Java Streams

More possible examples: A stream ascii character counter:

Counts how many ascii characters are read/written via the stream. Even can create histograms and statistics of the characters or character sequences.

A filter for writing only letters and digits while dropping the other characters.

Compression component that compresses the data according to any compression algorithm (like Lampell-Ziv)

Adapter

Moshe Fresko

Bar-Ilan University

2005-2006 - תשס"ו

Design Patterns Course

Adapter Intent: Convert the interface of a class into another interface clients

expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

Motivation: Sometimes a toolkit class that’s designed for reuse isn’t reusable only

because its interface doesn’t match the domain-specific interface an application requires.

The interface of graphical objects is defined by an abstract class Shape We define LineShape and PolygonShape TextShape is relatively hard so we want to use an already existing class

TextView. It is unpractical to take and change the source-code

Using Adapter in one of two ways By inheriting Shape’s interface and TextView’s implementation By composing TextView’s instance within a TextShape

Adapter – Motivation

Adapter – Applicability

Use the Adapter pattern when You want to use an existing class, and its

interface does not match the one you need. You want to create a reusable class that

cooperates with unrelated and unforeseen classes.

(object adapter) You need to use several existing subclasses, but it is impractical to adapt their interface by sub-classing every one.

Adapter – Structure

Class

Adapter

Object

Adapter

Adapter – Participants

Target defines the domain-specific interface that Client uses.

Client collaborates with objects conforming by the Target

interface

Adaptee defines an existing interface that needs adapting

Adapter adapts the interface of Adaptee to the Target interface

Adapter – Consequences

Class Adapter Adapts Adaptee to Target by committing to a concrete

Adaptee class. As a consequence, a class adapter won’t work when we want to adapt a class and all its subclasses.

Lets Adapter override some of Adaptee’s behavior, since Adapter is a subclass of Adaptee.

Introduces only one object, and no additional pointer indirection is needed to get to the Adaptee.

Object Adapter Lets a single Adapter work with many Adaptees. Makes it harder to override Adaptee behavior.

Adapter – Consequences

Other issues How much adapting does Adapter need to do? Pluggable Adapters Two-way adapters