comp 121 week 12: decorator and adapter design patterns
TRANSCRIPT
COMP 121COMP 121
Week 12: Decorator and Week 12: Decorator and Adapter Design PatternsAdapter Design Patterns
Decorator Design PatternDecorator Design Pattern
Intent: augment objects with new responsibilitiesIntent: augment objects with new responsibilitiesUse when:Use when:– Extension by subclassing is impractical (want to add Extension by subclassing is impractical (want to add
responsibilities to individual objects, not an entire responsibilities to individual objects, not an entire class)class)
– Responsibilities can be withdrawnResponsibilities can be withdrawn
Decorator implements the same interface as the Decorator implements the same interface as the object it decoratesobject it decoratesA "shell" or "wrapper" around an objectA "shell" or "wrapper" around an object– Requests that come in to the decorator are "forwarded" Requests that come in to the decorator are "forwarded"
to the object it decoratesto the object it decorates
Decorator Design Pattern (cont’d)Decorator Design Pattern (cont’d)
The key to a successful Decorator is to have a The key to a successful Decorator is to have a set of objects defined by an interfaceset of objects defined by an interface
Decorator implements the interface and takes an Decorator implements the interface and takes an object of that interface type as a parameter of its object of that interface type as a parameter of its constructor, which it saves internallyconstructor, which it saves internally
When a method is called on the decorator:When a method is called on the decorator:– May do some pre-processing before calling the same May do some pre-processing before calling the same
method on the decorated objectmethod on the decorated object– May do some post-processing on the results returned May do some post-processing on the results returned
from the same method in the decorated objectfrom the same method in the decorated object
Why Use a Decorator PatternWhy Use a Decorator Pattern
More flexibility than inheritanceMore flexibility than inheritance– Responsibilities can be added or removed at runtime)Responsibilities can be added or removed at runtime)
Avoids feature-laded classes high up in the Avoids feature-laded classes high up in the hierarchyhierarchy
A "pay-as-you-go" approach to adding A "pay-as-you-go" approach to adding responsibilitiesresponsibilities– Can define a simple classCan define a simple class– Add functionality incrementally with decoratorsAdd functionality incrementally with decorators
Decorator Example 1: SunglassesDecorator Example 1: Sunglasses
People “decorate” themselves in many different ways People “decorate” themselves in many different ways (for example clothing, makeup, jewelry, glasses)(for example clothing, makeup, jewelry, glasses)Sunglasses intercept incoming light and provide modified Sunglasses intercept incoming light and provide modified light to the eyeslight to the eyes– The eyes still get basically the same type of input (stream of light The eyes still get basically the same type of input (stream of light
into the eyes)into the eyes)– Input (light) is transformed by the sunglasses, but is still a form Input (light) is transformed by the sunglasses, but is still a form
of light (not converted into sound or smell)of light (not converted into sound or smell)
Eyes take in light whether or not the decorator (pair of Eyes take in light whether or not the decorator (pair of sunglasses) is presentsunglasses) is present– This “transparent” property of Decorator is what allows This “transparent” property of Decorator is what allows
Decorators to be chained togetherDecorators to be chained together– Person may wear contact lenses AND sunglassesPerson may wear contact lenses AND sunglasses
Decorator Example 2: Audio Decorator Example 2: Audio Enhancers/FiltersEnhancers/Filters
Electronic devices or software can be used to Electronic devices or software can be used to enhance, morph, or disguise your voiceenhance, morph, or disguise your voice– Change vocal pitch and timbre or apply other effects Change vocal pitch and timbre or apply other effects
such as volume or vibratosuch as volume or vibrato
Filter changes the audio streamFilter changes the audio stream– Input is an audio streamInput is an audio stream– Output is an audio streamOutput is an audio stream
Audio may be passed through a series of filters Audio may be passed through a series of filters to get the sound qualities desiredto get the sound qualities desired– Chain of decoratorsChain of decorators
Used with musical instruments, tooUsed with musical instruments, too
Decorator Example 3: Java File I/ODecorator Example 3: Java File I/O
Basic I/O classes are InputStream, Basic I/O classes are InputStream, OutputStream, Reader and WriterOutputStream, Reader and WriterNeed to add behaviors to the stream to get the Need to add behaviors to the stream to get the desired resultsdesired results– BufferedInputStream adds buffering for performanceBufferedInputStream adds buffering for performance– DataInputStream adds input of primitive data typesDataInputStream adds input of primitive data types
FileInputStream in = new FileInputStream("test.dat"); BufferedInputStream bin = new BufferedInputStream(in);DataInputStream dbin = new DataInputStream(bin);
Decorator Example 4: Unmodifiable Decorator Example 4: Unmodifiable CollectionCollection
List<Product> products = List<Product> products = newnew ArrayList<Product>(); ArrayList<Product>();
products.add(products.add(newnew Product("Book")); Product("Book"));products.add(products.add(newnew Product("Game")); Product("Game"));
Collection<Product> readOnlyProducts = Collection<Product> readOnlyProducts = newnew UnmodifiableCollection<Product>(products); UnmodifiableCollection<Product>(products);
Product p = readOnlyProducts.get(1); // returns GameProduct p = readOnlyProducts.get(1); // returns GamereadOnlyProducts.add(readOnlyProducts.add(newnew Product(...)); // Throws exception Product(...)); // Throws exception
products.add(products.add(newnew Product("Puzzle")); Product("Puzzle"));
intint numProducts = readOnlyProducts.size(); // returns 3 numProducts = readOnlyProducts.size(); // returns 3
publicpublic classclass CollectionDecorator<E> CollectionDecorator<E> implementsimplements Collection<E> { Collection<E> {
protectedprotected Collection<E> coll; Collection<E> coll;
publicpublic CollectionDecorator(Collection<E> c) { CollectionDecorator(Collection<E> c) { coll = c;coll = c; }}
publicpublic booleanboolean add(E obj) { add(E obj) { returnreturn coll.add(obj); coll.add(obj); }}
publicpublic intint size() { size() { returnreturn coll.size(); coll.size(); }}
// Other methods similar// Other methods similar
}}
publicpublic classclass IteratorDecorator<E> IteratorDecorator<E> implementsimplements Iterator<E> { Iterator<E> {
protectedprotected Iterator<E> iter; Iterator<E> iter;
publicpublic IteratorDecorator(Iterator<E> it) { IteratorDecorator(Iterator<E> it) { iter = it;iter = it; }}
publicpublic booleanboolean hasNext() { hasNext() { returnreturn iter.hasNext(); iter.hasNext(); }}
publicpublic E next() { E next() { returnreturn iter.next(); iter.next(); }}
publicpublic voidvoid remove() { remove() { iter.remove(); iter.remove(); }}}}
publicpublic classclass UnmodifiableCollection<E> UnmodifiableCollection<E> extendsextends CollectionDecorator<E> { CollectionDecorator<E> {
publicpublic UnmodifiableCollection(Collection<E> coll) { UnmodifiableCollection(Collection<E> coll) {
supersuper(coll);(coll); }}
publicpublic booleanboolean add(E obj) { add(E obj) {
throwthrow newnew UnsupportedOperationException("add not supported"); UnsupportedOperationException("add not supported"); }}
// Similar implementation for all methods that would change contents// Similar implementation for all methods that would change contents publicpublic Iterator<E> iterator() { Iterator<E> iterator() {
returnreturn newnew UnmodifiableIteratorUnmodifiableIterator<E>(coll.iterator());<E>(coll.iterator()); }}
}}
publicpublic classclass UnmodifiableIterator<E> UnmodifiableIterator<E> extendsextends IteratorDecorator<E> { IteratorDecorator<E> {
publicpublic UnmodifiableIterator(Iterator<E> iter) { UnmodifiableIterator(Iterator<E> iter) {
supersuper(iter);(iter); }}
@Override@Override publicpublic voidvoid remove() { remove() {
throwthrow newnew UnsupportedOperationException("remove not UnsupportedOperationException("remove not supported");supported");
}}}}
Question:Question:
How does the Decorator design pattern How does the Decorator design pattern differ from the Strategy design pattern?differ from the Strategy design pattern?
Answer:Answer:
The Decorator pattern changes the “skin” of an The Decorator pattern changes the “skin” of an objectobject– The decorator is a wrapper or outer layer that The decorator is a wrapper or outer layer that
changes the behavior of an objectchanges the behavior of an object– The object doesn’t know about its decoratorsThe object doesn’t know about its decorators
The Strategy pattern changes the “guts”The Strategy pattern changes the “guts”– The strategy is changed by using a different strategy The strategy is changed by using a different strategy
object that alters or extends the behavior of an objectobject that alters or extends the behavior of an object– The object knows about the available strategiesThe object knows about the available strategies
Adapter Design PatternAdapter Design Pattern
Intent:Intent:– Convert the interface of a class into another interface that the Convert the interface of a class into another interface that the
clients expectclients expect– Lets classes work together that otherwise couldn't because of Lets classes work together that otherwise couldn't because of
incompatible interfacesincompatible interfaces
Use when:Use when:– You want to use an existing class and its interface doesn't match You want to use an existing class and its interface doesn't match
the one you needthe one you need– You want to create a reusable class that cooperates with You want to create a reusable class that cooperates with
unrelated or unforeseen classes (classes that don't have unrelated or unforeseen classes (classes that don't have compatible interfaces)compatible interfaces)
Another type of “shell” or “wrapper” around an objectAnother type of “shell” or “wrapper” around an object– Requests that come in to the adapter are forwarded to the object Requests that come in to the adapter are forwarded to the object
being adapted, but the actual method being called is differentbeing adapted, but the actual method being called is different
Adapter Example 1: Socket WrenchAdapter Example 1: Socket Wrench
A socket attaches to a ratchet, provided A socket attaches to a ratchet, provided that the size of the drive is the samethat the size of the drive is the sameTypical drive sizes in the United States are Typical drive sizes in the United States are 1/2" and 1/4“1/2" and 1/4“– A 1/2" drive ratchet will not fit into a 1/4" drive A 1/2" drive ratchet will not fit into a 1/4" drive
socket unless an adapter is usedsocket unless an adapter is used– A 1/2" to 1/4" adapter has a 1/2" female A 1/2" to 1/4" adapter has a 1/2" female
connection to fit on the 1/2" drive ratchet, and connection to fit on the 1/2" drive ratchet, and a 1/4" male connection to fit in the 1/4" drive a 1/4" male connection to fit in the 1/4" drive socketsocket
Adapter Example 2: Travel Adapter Adapter Example 2: Travel Adapter KitsKits
In different parts of the world, different In different parts of the world, different wattages and outlet types make it wattages and outlet types make it impossible to use personal appliances impossible to use personal appliances (shavers, hair dryers, etc.) without (shavers, hair dryers, etc.) without modificationmodificationA travel adapter kit allows you to:A travel adapter kit allows you to:– Plug your appliance into a converter to Plug your appliance into a converter to
convert the wattageconvert the wattage– Plug the converter into the wall outlet by Plug the converter into the wall outlet by
adapting the plug typeadapting the plug type
Adapter Example 3: Replacing Adapter Example 3: Replacing Legacy or 3rd Party SoftwareLegacy or 3rd Party Software
The adapter pattern is commonly used in The adapter pattern is commonly used in applications where some third party software is applications where some third party software is being replaced with some other softwarebeing replaced with some other softwareRather than rewrite the application to use the Rather than rewrite the application to use the new software interface, use an adapter to adapt new software interface, use an adapter to adapt the old interface to the new interface:the old interface to the new interface:– The application code calls the old interface, but is now The application code calls the old interface, but is now
making those requests via the adaptermaking those requests via the adapter– The adapter converts the requests to requests that The adapter converts the requests to requests that
are compatible with the new softwareare compatible with the new software– The adapter may do some pre- or post-processing in The adapter may do some pre- or post-processing in
order to adapt requestorder to adapt request
Adapter Code Example Adapter Code Example publicpublic classclass Product { Product {
publicpublic Sku Sku getSkugetSku() {() { returnreturn sku; sku; }}
publicpublic voidvoid setSku(Sku sku) { setSku(Sku sku) { thisthis.sku = sku;.sku = sku; }}
publicpublic Money getCost() { Money getCost() { returnreturn cost; cost; }}
publicpublic voidvoid setCost(Money cost) { setCost(Money cost) { thisthis.cost = cost;.cost = cost; }}
publicpublic Money calculatePrice() { … } Money calculatePrice() { … }
publicpublic Money calculateMarkup() { … } Money calculateMarkup() { … }}}
// We want to use this existing class in place of Product// We want to use this existing class in place of Productpublicpublic classclass InventoryItem { InventoryItem {
privateprivate String barCode; String barCode; privateprivate String itemName; String itemName; privateprivate doubledouble purchasePrice; purchasePrice; privateprivate doubledouble salePrice; salePrice;
publicpublic doubledouble sellsFor() { sellsFor() { returnreturn salesPrice; salesPrice; }}
publicpublic String getBarCode() { String getBarCode() { returnreturn barCode; barCode; }}
// More methods here// More methods here}}
publicpublic interfaceinterface Product { Product { SkuSku getSku(); getSku(); voidvoid setSku(Sku sku); setSku(Sku sku);
Money getCost();Money getCost(); voidvoid setCost(Money cost); setCost(Money cost);
Money calculatePrice();Money calculatePrice(); Money calculateMarkup();Money calculateMarkup();
// More methods…// More methods…
}}
publicpublic classclass InventoryItemToProductAdapter { InventoryItemToProductAdapter {
privateprivate InventoryItem item; InventoryItem item;
publicpublic InventoryItemToProductAdapter(InventoryItem i) { InventoryItemToProductAdapter(InventoryItem i) { item = i;item = i; }}
publicpublic voidvoid setCost(Money cost) { setCost(Money cost) { item.setPurchasePrice(cost);item.setPurchasePrice(cost); }}
publicpublic Money calculatePrice() { Money calculatePrice() { returnreturn newnew Money(item.sellsFor()); Money(item.sellsFor()); }}
// More methods…// More methods…}}
/*/* * Now that we have the adapter, we can add InventoryItem* Now that we have the adapter, we can add InventoryItem * objects to a list of products and treat them like any* objects to a list of products and treat them like any * other product* other product */*/ List<Product> products = List<Product> products = newnew ArrayList<Product>(); ArrayList<Product>(); InventoryItem item = InventoryItem item = newnew InventoryItem(…); InventoryItem(…); products.add(products.add(newnew InventoryItemToProductAdapter(item)); InventoryItemToProductAdapter(item));
… …
// Having a half-off sale// Having a half-off sale forfor(Product product : products) {(Product product : products) { product.setCost(product.getCost().div(2));product.setCost(product.getCost().div(2)); }}
Question?Question?
How does the Adapter design pattern How does the Adapter design pattern differ from the Decorator design pattern?differ from the Decorator design pattern?
Answer:Answer:
The Decorator pattern only changes the The Decorator pattern only changes the object’s responsibilities, not its interfaceobject’s responsibilities, not its interface
The Adapter pattern changes the object’s The Adapter pattern changes the object’s interface, often without changing its interface, often without changing its responsibilitiesresponsibilities
Questions?Questions?