Adapter Pattern · 2017. 9. 28. · Adapter Pattern Solution Solution: Build a wrapper class....

Post on 24-Sep-2020

2 views 0 download

Transcript of Adapter Pattern · 2017. 9. 28. · Adapter Pattern Solution Solution: Build a wrapper class....

Adapter Pattern

Or building a wrapper class

Adapter Purpose

Purpose: Create a wrapper around an existing class that you don’t control. The wrapper makes the object conform to your needs.

Problem (or When to Use): Have a class that almost does what I need.

Has all (or almost) the right behavior, but has wrong access methods.

Adapter Pattern Solution

Solution: Build a wrapper class.

Implementation: Build a wrapper class around the existing class. Use your class instead.

Consequences: Allows pre-existing classes to be used in your code. Will not work if existing class is missing some key behavior.

So What’s a Wrapper?

A class that encompasses another class (or method, or…)

We’ve seen examples with the composition notation.

Why would this indicate that one class wraps around another?

WoodPlankBarn

Java Example: Integer

Example : The Integer class in Java. This class wraps itself around the “int”

datatype. So not quite like composition, but close.

Why did Java developers want to do this? int does everything they want, except cannot be

treated as an object.

Solution: Integer class wraps int, and now extends Object class. So the Integer has the int and is an Object.

Object Integer

Java Example: Integer (cont.)

What’s the advantage of this wrapper? Some methods can require an Object as a parameter.

e.g., void toString(Object o)

e.g., boolean equals(Object o)

(actually a method in the Object class)

Can accept almost anything!

But can’t accept an int (or char, or float, or double, or boolean).

Problem: can’t pass int as an Object. Solution: build wrapper called Integer.

This is an adapter class!

Java Example: Integer (cont.)

What would the code look like? (pseudo…)

public class Integer

{

private int i; //creates an int inside this class.

//This is what we are wrapping around!

public Integer(int iValue)

{

i = iValue; //sets the int’s value when instantiated

}

public int getInteger() //actually called intValue()

{

return i;

}

public String toString()

{

return “”+i;

}

}

Java Example: Integer (cont.)

So now when a method requires an Object, we can pass it the integer rather than the int.

toString(3) //ERROR

toString(Integer(3)) //Ahhhhh… wrapped!

Another Example: EmailSender

S’pose I am asked to write an email sender.

Suppose project already has an existing class SpamSender()

existing class has methods for

sendSpam

setSubject

setBody

Suppose that the sendSpamTo must be given multiple addresses

Another Example (cont.)

1. I’d prefer my code was written with a method called sendEmail() rather than sendSpam()

2. My code only provides one email address.

3. sendSpam() returns the # of bad email addresses, but I don’t care about that.

4. But, I don’t want to rewrite everything!

Solution: A wrapper – Adapter pattern Why not solve with a Façade? Because we are

changing the behavior, not just hiding existing behaviors.

Another Example (cont.)

public class EmailSender

{

private EmailAddress fakeAddress = new EmailAddress(blubber@blubber.com);

private SpamSender spam;

public EmailSender()

{

spam = new SpamSender(); //creates a SpamSender inside this class.

} //This is what we are wrapping around!

public void sendEmail(EmailAddress sendToRealAddress)

{

spam.sendSpam(sendToRealAddress, fakeAddress);

}

}

I don’t have two addresses, so I just give it a fake one.

Another Example (cont.)

So what’s the UML picture?

EmailSender

+sendEmail(:EmailAddress):void

SpamSender

+sendSpam(:EmailAddress, :EmailAddress):int

1

1

Another Example (cont.)

Collaboration diagram

:Driver

:EmailSender

:SpamSender

1: sendEmail(:EmailAddress) : void

1.1: sendSpam(:EmailAddress, :EmailAddress) : int

Adapter Pattern UML

UML diagram:

AdapteeAdapter Now can use Adapter in place of Adaptee.

Adapter Pattern UML May Vary

As I’ll say many times, design patterns may be (slightly) altered to fit your needs.

They’re just patterns.

Consider the following: Before the Adapter Pattern…

Client ExistingClass

+methodCall()

Adaptee

+adapteeCall()

Almost does what we want, but not quite.

Adapter Pattern UML Option 2

Common alteration of Adapter:

Client ExistingClass

+methodCall()

AdapteeAdapter

+methodCall() +adapteeCall()

Use this when Client, ExistingClass, and Adaptee already exist. Adapter takes the interface of Adaptee and makes it work with the ExistingClass. So client calls “methodCall” and gets behavior of “adapteeCall”.

What’s the advantage of this approach? The Client class never even knows that the wrapper class exists. Taking advantage of polymorphism! Same method call, different behavior because deals with Adaptee.

Adapter UML: Why Not Inheritance?

Well, it might be, (as above UML shows) but not usually.

We want to adapt something to our own purposes and “hide” the old inappropriate version.

For example, we want to hide the SpamSender and replace it with an EmailSender.

Inheritance will extend existing code, but may not hide the old code.

If EmailSender inherits from the SpamSender, then the interface will include the inherited method sendSpam. Aurgh! We wanted to get rid of that, or hide it.

We could override the sendSpam, but then we have an interface with a misleading method name (“sendSpam”) that doesn’t sound anything like “sendEmail”.

Better option: Use composition to completely hide the old code.

How Different From Façade?

Very similar – dealing with an interface to pre-existing classes.

Adapter provides an interface without simplifying. Adds new features or a new way to access old features. polymorphism likely composition likely (almost always) aggregation not likely

Façade provides simplified interface. Never adds new features. polymorphism less likely composition likely aggregation also likely

Sometimes, the adaptation might appear to simplify. In those cases, you are creating both an adapter and a façade.

OK, Your Turn

Create 2 teams.

Each team must adapt the Java LinkedList API to be a Stack.

In other words, turn the existing linked list into a stack.

If unclear, justify why it is not just the façade pattern.

If stuck, consider other team’s answer.