
어댑터 패턴은 래퍼(Wrapper)라고도 불리며, 클라이언트와 구현된 인터페이스를 분리해 후에 인터페이스가 바뀌더라도 그 변경 내역은 어댑터에 캡슐화되기 때문에 클라이언트는 바뀔 필요가 없어진다.
어댑터 패턴은
장점
단일 책임 원칙(SRP) 준수 : 프로그램의 기본 로직에서 인터페이스 또는 데이터 변환 코드를 분리할 수 있다.
개방 폐쇄 원칙(OCP) 준수 : 클라이언트가 어댑터와 작동하는 한, 기존 코드를 손상시키지 않고 새로운 어댑터들을 도입할 수 있다.
단점
사용 시기
기존 클래스를 사용하고 싶지만 그 인터페이스가 나머지 코드와 호환되지 않을 때
부모 클래스에 추가할 수 없는 공통 기능들이 없는 여러 기존 자식 클래스들을 재사용하려고 할 때
어댑터는 한 객체의 인터페이스를 구현하고 다른 객체는 래핑한다.
합성된 멤버에게 위임을 이용한다.
런타임 중에 어댑티가 결정되어 유연하다.
한 방향으로 역할한다.
모든 프로그래밍 언어로 구현할 수 있다.

Adaptee(Service) : 어댑터 대상 객체, 호환시키려는 객체
Target(Client Interface) : Adapter가 구현하는 인터페이스
Adapter : Client와 Adaptee(Service) 중간에서 호환성이 없는 둘을 연결
Adaptee(Service)를 따로 클래스 멤버로 설정하고 위임을 통해 동작을 매치시킨다.Client : 기존 시스템(어댑티)을 어댑터를 통해 이용하려는 쪽. Client Interface를 통하여 Service를 이용할 수 있게 된다.
어댑터가 동시에 두 객체의 인터페이스를 상속한다.
객체를 래핑할 필요가 없고, 따로 객체 구현없이 바로 코드 재사용이 가능하다.
양방향으로 역할한다.
다중 상속이 가능한 언어에서만 사용이 가능하며, 죽음의 다이아몬드 문제 등 다중 상속의 문제 때문에 권장되지 않는 방법이다.

Adaptee(Service) : 어댑터 대상 객체, 호환시키려는 객체
Target(Cient Interface) : Adapter 가 구현하는 인터페이스.
Adapter : Client 와 Adaptee(Service) 중간에서 호환성이 없는 둘을 연결
Client : 기존 시스템(어댑티)을 어댑터를 통해 이용하려는 쪽. Existing Class를 통하여 Service를 이용할 수 있게 된다.
호환되지 않는 인터페이스가 있는 클래스들이 있다.
클라이언트 인터페이스를 선언하고 클라이언트들이 어댑티(서비스)와 통신하는 방법을 기술한다.
어댑터 클래스를 생성하고 클라이언트 인터페이스를 상속한다.
어댑티 객체에 참조를 저장하기 위해 어댑터 클래스에 필드를 추가한다.
클라이언트 인터페이스의 모든 메소드를 어댑터 클래스에서 구현한다.

// RoundHole(둥근 구멍) 및 RoundPeg(둥근 못)라는 호환되는 인터페이스들이 있는
// 두 개의 클래스가 있다고 가정해봅시다.
class RoundHole is
constructor RoundHole(radius) { ... }
method getRadius() is
// 구멍의 반지름을 반환하세요.
method fits(peg: RoundPeg) is
return this.getRadius() >= peg.getRadius()
class RoundPeg is
constructor RoundPeg(radius) { ... }
method getRadius() is
// 못의 반지름을 반환하세요.
// 그러나 SquarePeg(직사각형 못)라는 호환되지 않는 클래스가 있습니다.
class SquarePeg is
constructor SquarePeg(width) { ... }
method getWidth() is
// 직사각형 못의 너비를 반환하세요.
// 어댑터 클래스를 사용하면 정사각형 못을 둥근 구멍에 맞출 수 있습니다. 어댑터
// 객체들은 RoundPeg(둥근 못) 클래스를 확장해 둥근 못들처럼 작동하게 해줍니다.
class SquarePegAdapter extends RoundPeg is
// 실제로 어댑터에는 SquarePeg(정사각형 못) 클래스의 인스턴스가 포함되어
// 있습니다.
private field peg: SquarePeg
constructor SquarePegAdapter(peg: SquarePeg) is
this.peg = peg
method getRadius() is
// 어댑터는 이것이 어댑터가 실제로 감싸는 정사각형 못에 맞는 반지름을
// 가진 원형 못인 것처럼 가장합니다.
return peg.getWidth() * Math.sqrt(2) / 2
// 클라이언트 코드 어딘가에…
hole = new RoundHole(5)
rpeg = new RoundPeg(5)
hole.fits(rpeg) // 참
small_sqpeg = new SquarePeg(5)
large_sqpeg = new SquarePeg(10)
hole.fits(small_sqpeg) // 이것은 컴파일되지 않습니다(호환되지 않는 유형)
small_sqpeg_adapter = new SquarePegAdapter(small_sqpeg)
large_sqpeg_adapter = new SquarePegAdapter(large_sqpeg)
hole.fits(small_sqpeg_adapter) // 참
hole.fits(large_sqpeg_adapter) // 거짓
using System;
namespace RefactoringGuru.DesignPatterns.Adapter.Conceptual
{
// The Target defines the domain-specific interface used by the client code.
public interface ITarget
{
string GetRequest();
}
// The Adaptee contains some useful behavior, but its interface is
// incompatible with the existing client code. The Adaptee needs some
// adaptation before the client code can use it.
class Adaptee
{
public string GetSpecificRequest()
{
return "Specific request.";
}
}
// The Adapter makes the Adaptee's interface compatible with the Target's
// interface.
class Adapter : ITarget
{
private readonly Adaptee _adaptee;
public Adapter(Adaptee adaptee)
{
this._adaptee = adaptee;
}
public string GetRequest()
{
return $"This is '{this._adaptee.GetSpecificRequest()}'";
}
}
class Program
{
static void Main(string[] args)
{
Adaptee adaptee = new Adaptee();
ITarget target = new Adapter(adaptee);
Console.WriteLine("Adaptee interface is incompatible with the client.");
Console.WriteLine("But with adapter client can call it's method.");
Console.WriteLine(target.GetRequest());
}
}
}
Adaptee interface is incompatible with the client.
But with adapter client can call it's method.
This is 'Specific request.'
namespace Wikipedia.Examples;
using System;
interface ILightningPhone
{
void ConnectLightning();
void Recharge();
}
interface IUsbPhone
{
void ConnectUsb();
void Recharge();
}
sealed class AndroidPhone : IUsbPhone
{
private bool isConnected;
public void ConnectUsb()
{
this.isConnected = true;
Console.WriteLine("Android phone connected.");
}
public void Recharge()
{
if (this.isConnected)
{
Console.WriteLine("Android phone recharging.");
}
else
{
Console.WriteLine("Connect the USB cable first.");
}
}
}
sealed class ApplePhone : ILightningPhone
{
private bool isConnected;
public void ConnectLightning()
{
this.isConnected = true;
Console.WriteLine("Apple phone connected.");
}
public void Recharge()
{
if (this.isConnected)
{
Console.WriteLine("Apple phone recharging.");
}
else
{
Console.WriteLine("Connect the Lightning cable first.");
}
}
}
sealed class LightningToUsbAdapter : IUsbPhone
{
private readonly ILightningPhone lightningPhone;
private bool isConnected;
public LightningToUsbAdapter(ILightningPhone lightningPhone)
{
this.lightningPhone = lightningPhone;
}
public void ConnectUsb()
{
this.lightningPhone.ConnectLightning();
}
public void Recharge()
{
this.lightningPhone.Recharge();
}
}
public class AdapterDemo
{
static void Main(string[] args)
{
ILightningPhone applePhone = new ApplePhone();
IUsbPhone adapterCable = new LightningToUsbAdapter(applePhone);
adapterCable.ConnectUsb();
adapterCable.Recharge();
}
}
Apple phone connected.
Apple phone recharging.