본문 바로가기
소프트웨어공학/디자인 패턴

Adapter 어댑터 패턴 - 구조, client 가 요구하는 인터페이스와 제공된 클래스의 인터페이스가 일치하지 않을 때 | Design Pattern 디자인 패턴

by javapp 자바앱 2021. 10. 10.
728x90

 

구조에 따른 패턴 분류

적용 범위 Scope 클래스 class
- 클래스 간 관계
- 주로 inheritance 사용
- 정적) 컴파일 시 결정됨
Adapter (class) (상속)
객체 object
- 객체 간 관계
- 주로 composition 사용
- 동적) 실행 시 변경 가능
Adapter (object) (구성)
Facade (퍼사드)
Composite
Decorator
Proxy
Bridge
Flyweight

 

인터페이스 관련 패턴

Adapter pattern

Facade pattern

Composite pattern

Bridge pattern

 

모두 구조 패턴에 속함

 

 

 


 

 

Adapter 구조 패턴

 

 

 

언제 ?

-> Interface mismatching

client 가 요구하는 인터페이스와 제공된 클래스의 인터페이스가 일치하지 않을 때

 

예시)

Client calls methodA(), Library class has methodB()

: Client는 methodA를 원하는데 라이브러리 클래스의 메소드 명은 methodB

 

Key Idea : 인터페이스 변환 - AdapteeinterfaceClient가 원하는 인터페이스로 변환

 

 

Client Adapter Adaptee
cals methodA() methodA(){
    adaptee.methodB();
}
methodB(){
   // ...\
}

Adapter 에 Client가 원하는 메소드를 가지고 있고, 호출 시 Adaptee의 메소드를 호출한다.

 

 

적용 방법

1. Object Adapter pattern (구성)

2. Class Adapter pattern (다중 상속)

 

 

Object Adapter pattern

장점) Composition 을 사용하여 adaptee에게 위임하기 때문에 flexible 하다.

단점) Adaptee 객체 만들어야 사용가능

adapter에 행동 추가 모든 subclass에게도 적용됨.

subclassadapt 가능

 

Class Adapter pattern

장점) Adaptee 객체를 만들지 않아도 된다. I don’t have to reimplement my entire adaptee.

단점) 상속 때문에 한 Adapter 클래스가 특정 Adaptee 클래스에만 적용 가능

Adapteesubclassadapt 하지 못함.

 

 

 

 


 

Object Adapter pattern using Composition(구성)

 

specificRequest() 는 Request 의 구현 

 

 

 

위임

인스턴스 불러와서 대신 시킴

 

 

 

Target <interface> : defines the interface that Client uses.

Adaptee               : defines an existing interface that needs adpating.

Adapter               : converts the adaptee's interface into the target interface. 

                           So, Adapter hides Adaptee's interface from Client

 

 

 

 

예제 코드

Diagram

Client Target Interface Adaptee
class DuckTestDrive

    // 제공된 클래스가 오리가 아니고 칠면조
   Turkey 칠면조 = new WildTrukey();

   // 오리(adapter)를 만들어야지.
   //Adapter wraps Adaptee.
   Duck 오리 =
   new RedDuck(칠면조);
   어댑터 ( 어댑티 );
 
   //calls 오리.
   오리.quack();
   오리.fly();
public interface Duck{
   public void quack();
   public void fly();
}
public interface Turkey{
   public void gobble();
   public void fly();
}

public class WildTurkey implements Turkey
{
   public void gobble(){ ... }
   public void fly() {.... }
}
Adapter public class RedDuck implements Duck { //TurkeyAdapter
  Turkey 칠면조; //COMPOSITION: 파라미터로 받아서 인스턴스 객체 내부에 저장
   public RedDuck(Turkey 칠면) { 칠면조 = 칠면; } // of adaptee
 
   public void quack() { 칠면조.gobble(); } //DELEGATION
   public void fly() { 칠면조.fly(); 칠면조.fly(); } // to adaptee
}
// ★
컴포지션을 이용해서 위임을 한다.

 

 

// * TARGET Interface
public interface Duck 
{
	public void quack();
	public void fly();
}


public class MallardDuck implements Duck {
	public void quack() {
		System.out.println("MallardDuck Quack");
	}
 
	public void fly() {
		System.out.println("I'm flying");
	}
}


// * Adapter
public class TurkeyAdapter implements Duck {
	Turkey turkey;			// Composition : 파라미터로 받아서 인스턴스 객체를 클래스 내부에 저장
 
	public TurkeyAdapter(Turkey turkey) { //of adaptee
		this.turkey = turkey;
	}
    
	public void quack() {
		turkey.gobble();		// Deletegation : Turkey가 대신 수행
	}
  
	public void fly() {			// to adaptee
		for(int i=0; i < 5; i++) {
			turkey.fly();
		}
	}
}
//*** Composition을 통해서 위임을 한다.

 

// * Adaptee
public interface Turkey 
{
	public void gobble();
	public void fly();
}

public class WildTurkey implements Turkey 
{
	public void gobble() {
		System.out.println("WildTurkey Gobble gobble");
	}
 
	public void fly() {
		System.out.println("I'm flying a short distance");
	}
}


public class DuckAdapter implements Turkey 
{
	Duck duck;
	Random rand;
 
	public DuckAdapter(Duck duck) {
		this.duck = duck;
		rand = new Random();
	}
    
	public void gobble() {
		duck.quack();
	}
  
	public void fly() {
		if (rand.nextInt(5)  == 0) {
		     duck.fly();
		}
	}
}

 

public class DuckTestDrive {
	public static void main(String[] args) {

		//제공된 클래스가 오리가 아니고 칠면조
		Turkey turkey = new WildTurkey();
		Duck duck = new MallardDuck();

		// 오리 어댑터를 생성
		Duck turkeyAdapter = new TurkeyAdapter(turkey);

		System.out.println("The Turkey says...");
		turkey.gobble();
		turkey.fly();
 
		System.out.println("\nThe Duck says...");
		testDuck(duck);

		// calls 오리 (Duck)
		System.out.println("\nThe TurkeyAdapter says...");
		testDuck(turkeyAdapter);
	}
 
	static void testDuck(Duck duck) {
		duck.quack();
		duck.fly();
	}
}

<실행 결과>

The Turkey says...
WildTurkey Gobble gobble
I'm flying a short distance

The Duck says...
MallardDuck Quack
I'm flying

The TurkeyAdapter says...
WildTurkey Gobble gobble
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance

Process finished with exit code 0

 

 


 

Class Adapter Pattern using Multiple Inheritance.

 

(C++) class Adapter : public TargetClass, private Adaptee (타겟의 Request 만 사용하게 하기 위해 / clientSpecificrequest 사용 불가 하게)

- Client에게 공개할 Target 클래스는 public 상속,

- Adapter 내부에서만 사용할 Adapteeprivate 상속.

 

class Adapter extends Adaptee implements Target

interface 를 통해 다중 상속의 효과를 얻을 수 있다.

 

 

public class Adaptee
{
    public void specificRequest(List list){
        System.out.println("specificRequest");
        for(Object o : list) System.out.println(o);
    }
}

 

public class Adapter extends Adaptee implements Target
{
    @Override
    public void request(List list) {
        specificRequest(list);
    }
}

 

public class Client {
    public static void main (String args[])
    {
        Adapter adapter = new Adapter();
        adapter.request(Arrays.asList(args));
    }
}

실행 결과

 

 


 

 

Old world Enumerators

New world Iterators

Writing the EnumerationIterator adapter

 

new world iterators
When Sun released their more recent
Collections classes they began using an
Iterator interface that, like Enumeration,
allows you to iterate through a set of items
in a collection, but also adds the ability to
remove items.

EnumerationIterator : Adapter
Iterator : Target interface
Enumeration : Adaptee interface

/*
Since we’re adapting Enumeration
to Iterator, our Adapter
implements the Iterator interface...
it has to look like an Iterator.
*/

public class EnumerationIterator implements Iterator 
{
	Enumeration enumeration;

	//The Enumeration we’re adapting.
	//We’re using composition so we stash(넣어 두다 숨기다)
	//it in an instance variable
	public EnumerationIterator(Enumeration enumeration) { // 구성
		this.enumeration = enumeration;
	}

	//The Iterator’s hasNext() method
	//is delegated to the Enumeration’s
	//hasMoreElements() method...
	public boolean hasNext() {
		return enumeration.hasMoreElements(); //위임
	}

	//... and the Iterator’s next() method
	//is delegated to the Enumerations’s
	//nextElement() method.
	public Object next() {
		return enumeration.nextElement();
	}

	//Unfortunately, we can’t support
	//Iterator’s remove() method, so
	//we have to punt (in other words,
	//we give up!). Here we just throw
	//an exception.
	public void remove() {
		throw new UnsupportedOperationException();
	}
}

 

적용

public class Client {
	public static void main (String args[]) {
		Vector v = new Vector(Arrays.asList(args));
		Iterator iterator = new EnumerationIterator(v.elements());
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

 

 

 

 


 

 

 

  • 국내 가전제품을 외국에서 사용한다고 할 때, 동일한 전압을 사용하지 않는다면 중간에 변환 코드가 필요하다. 이러한 변환 코드를 어댑터 구조 패턴이라고 한다.
  • 인터페이스로 인해 함께 사용하지 못하는 클래스를 함께 사용하도록 하는 패턴
  • 호환성이 없는 인터페이스 때문에 함께 동작할 수 없는 클래스들을 함께 동작하도록 해준다.

댓글