Fork me on GitHub

Adapter

Motivation

Imagine that we need to develop a graphical editor which should be able to draw various graphical shapes like line, circle, rectangle and text. All of our graphical elements are subclass of the base class Shape. So, we will have LineShape, CircleShape, RectangeShape and TextShape.

The implementation of the TextShape is not easy. We need to implement a lot of complex functionalities, such as text buffering, text bolding, text coloring, undo, redo, ‘what you see is what you get’, etc. We have found an open source text library which implements pretty much all of the text functionality which we are looking for.

Why not adapt an existing text library, so that we can reuse already implemented functionality for our graphical editor? But, in order to use the existing text library, we must adapt interfaces from the existing text library to our interfaces.

The process of adaptation of the existing interfaces is an example of the Adapter pattern.

The adapter allows us to access the interface of an existing class from another interface.

Story

Adapters are often used in daily life, for example, an electrical adapter is a device that converts attributes of one electrical device or system to those of an otherwise incompatible device or system. Some modify power or signal attributes, while others merely adapt the physical form of one electrical connector to another.

Image

alt text

Lionel Allorge, Adaptateur de prise française en prise suisse 2, CC BY-SA 3.0

UML

Class Adapter

Object Adapter

Structure

We can have two implementations, the Class adapter and the Object adapter.

The Class adapter extends the Adaptee class.
The Object adapter injects Adaptee object into the Adapter class.

The target interface defines the domain-specific interface used by the Client.
The Client class uses the target interface.
The Adaptee class defines an existing interface where adaption will be applied.
The Adapter class adapts interface Adaptee to the Target.

Implementation

Class Adapter

Target.java

package com.hundredwordsgof.adapter.clazz;

/**
 * 
 * Target interface, defines domain-specific interface to which Adaptee will be adapted 
 *
 */
public interface Target {

	String request();	
}

Adaptee.java

package com.hundredwordsgof.adapter.clazz;

/**
 * 
 * Adaptee class, interface which will be adapted 
 *
 */
public class Adaptee {

	public String specialRequest(){
		return "specialRequest";
	}
}

Adapter.java

package com.hundredwordsgof.adapter.clazz;

/**
 * 
 * Adapter class, adapts Adaptee to the Target interface
 *
 */
public class Adapter extends Adaptee implements Target {
	
	public String request() {
		return this.specialRequest();
	}
}

Object Adapter

Target.java

package com.hundredwordsgof.adapter.object;

/**
 * 
 * Target interface, defines domain-specific interface to which Adaptee will be adapted 
 *
 */
public interface Target {

	String request();	
}

Adaptee.java

package com.hundredwordsgof.adapter.object;

/**
 * 
 * Adaptee class, interface which will be adapted 
 *
 */
public class Adaptee {

	public String specialRequest(){
		return "specialRequest";
	}
}

Adapter.java

package com.hundredwordsgof.adapter.object;

/**
 * 
 * Adapter class, adapts Adaptee to the Target interface
 *
 */
public class Adapter implements Target {

  private Adaptee adaptee;

  public Adapter(Adaptee adaptee) {
    this.adaptee = adaptee;
  }

  public String request() {
    return adaptee.specialRequest();
  }
}

Usage

ClazzAdapterTest.java

package com.hundredwordsgof.adapter;

import static org.junit.Assert.*;
import org.junit.Test;
import com.hundredwordsgof.adapter.clazz.Adapter;
import com.hundredwordsgof.adapter.clazz.Target;

/**
 * Test implementation of the Adapter(object) pattern.
 */
public class ClazzAdapterTest {

  @Test
  public void testAdapter() {

    // creates Adapter
    Target target = new Adapter();

    assertEquals("specialRequest", target.request());
  }
}

ObjectAdapterTest.java

package com.hundredwordsgof.adapter;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.hundredwordsgof.adapter.object.Adaptee;
import com.hundredwordsgof.adapter.object.Adapter;
import com.hundredwordsgof.adapter.object.Target;

/**
 * Test implementation of the Adapter(object) pattern.
 */
public class ObjectAdapterTest {

  @Test
  public void testAdapter() {

    // creates Adaptee
    Adaptee adaptee = new Adaptee();

    // creates Adapter
    Target target = new Adapter(adaptee);

    assertEquals("specialRequest", target.request());
  }
}