본문 바로가기

PROGRAMMING/Design Pattern

[GoF] 어댑터 (Adapter) 패턴

어댑터 (Adapter) 패턴 구조 패턴

클래스의 인터페이스를 클라이언트가 요구하는 인터페이스로 변환합니다. 어댑터를 통해 클라이언트는 직접적으로 호환되지 않는 클래스를 연결해서 사용할 수 있습니다.


 


우리는 살면서 어댑터라는 개념을 가진 물건을 한번 쯤 사용해본 적이 있을 것이다. 핸드폰을 충전할 때 사용하는 전원 어댑터, 컴퓨터와 모니터 사이에 연결하는 HDMI 어댑터 등등... 이처럼 어댑터는 서로 다른 물체를 간접적으로 연결하게 하는 역할을 가지고 있다. GoF는 이 어댑터의 개념을 소프트웨어 설계에 적용하였다.

클라이언트는 클래스가 다양한 인터페이스에 대응하는것을 원하기도 하는데, 그럴 경우에 클래스에 인터페이스를 직접 구현하는것도 방법이지만, 그것은 SOLID의 개방-폐쇄의 원칙에 어긋나기도 하고 (지구라는 클래스를 교육 자료로 활용하기 위해서 직접 지구 클래스 안에 교육 자료로 활용될 지구를 구현하는 것과 같은 이치이다!) 라이브러리를 사용하는 경우 수정이 불가능하기도 하다.

그래서, 클래스와 인터페이스 사이에 어댑터의 개념을 가진 클래스를 만들어 클라이언트에게 클래스에 대한 인터페이스를 제공한다. 클라이언트는 클래스와 연결된 어댑터를 인터페이스로써 활용할 수 있다. 그러므로, 어댑터 패턴을 이용하여 클래스에 대한 다양한 인터페이스와의 의존성을 분리할 수 있다.

어댑터 패턴은 구현 형태에 따라 두가지로 나눌 수 있다: 객체의 참조에 의한 어댑터와, 클래스의 상속에 의한 어댑터로 구분된다. 객체의 참조에 의한 어댑터는, 어댑터 내에 인터페이스로 활용할 객체를 참조하여 어댑터의 기능을 수행한다. 반면에, 클래스의 상속에 의한 어댑터는 인터페이스로 활용할 클래스를 상속받아 추가적으로 인터페이스를 구현하는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class Adapter
{
    public interface IAdapter // 인터페이스
    {
        void OperateAdapter();
    }
 
    public class Adaptee
    {
        public void OperateAdaptee()
        {
            Console.WriteLine("Operate Adaptee");
        }
    }
 
    public class ReferenceAdapter : IAdapter // 객체의 참조에 의한 어댑터
    {
        private Adaptee _adaptee;
 
        public ReferenceAdapter(Adaptee adaptee)
        {
            _adaptee = adaptee;
        }
 
        public void OperateAdapter()
        {
            _adaptee.OperateAdaptee();
        }
    }
 
    public class ImplementationAdapter : Adaptee, IAdapter // 클래스의 상속에 의한 어댑터
    {
        public void OperateAdapter()
        {
            OperateAdaptee();
        }
    }
 
    public static void Main(string[] args)
    {
        IAdapter adapter;
 
        adapter = new ReferenceAdapter(new Adaptee());
        adapter.OperateAdapter();
 
        adapter = new ImplementationAdapter();
        adapter.OperateAdapter();
    }
}
cs

IAdapter 인터페이스에 참조에 의한 어댑터와 상속에 의한 어댑터를 참조하여 OperateAdapter() 함수를 호출하였다. 결과는 두 어댑터 모두 Adaptee의 OperateAdaptee() 함수를 호출하여 "Operate Adaptee"를 출력하였다.