1. 어댑터 패턴이란?
- 클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴.
- 두 객체 사이의 래퍼 역할을 함.
- 호환되지 않는 객체들이 협업할 수 있게 함.
- 기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴.
- 하나의 객체에 대한 호출을 캐치하고 두 번째 객체가 인식할 수 있는 형식과 인터페이스로 변환시켜줌.
2. 어댑터 패턴을 사용하는 경우
- 버그가 없이 이미 존재하는 클래스를 재사용하는 경우
- 이미 만들어진 클래스를 새로운 인터페이스에 맞게 개조시키는 경우
- 오픈소스를 사용하거나 프로젝트 중간에 합류해서 작업해야 하는 경우
3. 어댑터 패턴의 장점
1) 호환성 : 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있음.
2) 보존성 : 기존의 두 소스는 수정할 필요가 없고, 어댑터 클래스만 추가되어 둘 사이를 연결해준다.
3) 확장성 : 기존의 클래스에 새로운 기능을 추가해서 신규 클래스 같은 기능을 하게 할 수 있음.
4) 캡슐화 : 상세한 내부 코드의 흐름을 몰라도 되고, 버그를 찾기 쉬움
4. 어댑터 패턴의 단점
1) 복잡성 증가 : 소스코드가 늘어나 코드의 복잡성을 증가시켜 유지보수가 어려워질 수 있음.
2) 처리시간 증가 : 어댑터가 중간에서 데이터를 변환하는 과정이 추가적인 처리 시간과 오버 헤드를 발생시킬 수 있음.
5. 코드 구현
1) 위임을 이용
- 두 개의 클래스 중 한 쪽 클래스의 함수를 다른 쪽 클래스에서 사용하고 싶을 때 사용한다.
- 아래 예시는 카드결제만 가능한 상황에서 카드가 없을 때 어댑터 패턴을 이용해 현금으로 계산하는 방법이다.
1. 카드 인터페이스를 상속받은 어댑터 클래스에서 현금 인터페이스 객체를 만들어준다.
2. 생성자를 이용해 어댑터 객체 생성시 현금 객체를 연결해준다.
3. 카드 인터페이스의 구현 함수를 오버라이드할 때 현금 객체의 결제 함수를 콜해준다.
using System;
namespace StudyCSharp
{
// 현금
public interface Cash
{
void Charge(); // 결제
}
// 카드
public interface Card
{
void Pay(); // 결제
}
// 지폐
public class Bill : Cash
{
int _money; // 보유한 현금의 양
public Bill(int money)
{
_money = money;
}
public void Charge()
{
Console.WriteLine("현금 {0}원 결제", _money);
}
}
// 체크카드
public class CheckCard : Card
{
int _money; // 카드 잔액
public CheckCard(int money)
{
_money = money;
}
public void Pay()
{
Console.WriteLine("카드 {0}원 결제", _money);
}
public void Lost()
{
Console.WriteLine("카드 분실");
}
}
// 어댑터 패턴
// 카드지만 현금을 이용할 수 있음
public class MoneyAdapter : Card
{
Cash cash;
public MoneyAdapter(Cash cash)
{
Console.WriteLine("어댑터 카드 생성");
this.cash = cash;
}
public void Pay()
{
Console.WriteLine("사용 가능한 카드가 없어 어댑터 카드로 대신 결재합니다.");
cash.Charge();
}
}
class Program
{
static void Main(string[] args)
{
Bill myBill = new Bill(10000); // 보유현금
CheckCard myCard = new CheckCard(5000); // 보유카드
// <상황>
// 카드결제만 가능한 상황, 처음에는 카드로 잘 결제를 했지만,
// 카드를 분실하여 두번째 결제시에는 현금으로 대신 결제
// 첫번째 결제 -> 카드가 있으므로 카드로 계산
myCard.Pay();
// 카드 분실
myCard.Lost();
// 카드로만 결제가 가능하기 때문에, 현재 보유한 현금으로 만들 수 있는 어댑터카드 생성
Card adapterCard = new MoneyAdapter(myBill);
// 두번째 결제 -> 어댑터 카드로 결제
adapterCard.Pay();
}
}
}
2) 상속을 이용
- 다중상속을 이용하도록 기존 클래스를 변경하여 실행코드는 동일하게 유지한채 출력을 바꾸고 싶을 때 사용할 수 있다.
- 새로운 인터페이스를 만들고, 기존 인터페이스만 상속되있던 것에 추가로 상속시켜주고, 새로운 인터페이스의 구현 함수를 오버라이드하여 정의해준뒤, 기존 인터페이스 오버라이드 함수에서 콜 해준다.
using System;
namespace StudyCSharp
{
// 현금
public interface Cash
{
void Charge(); // 결제
}
// 카드
public interface Card
{
void Pay(); // 결제
}
// 기존 클래스
//public class Adapter : Cash
//{
// public void Charge()
// {
// Console.WriteLine("현금 결제");
// }
//}
// 어댑터 클래스 - 다중상속 이용
public class Adapter : Cash, Card
{
public void Charge()
{
Pay();
}
//////////////////////////////////////////////////////////////
public void Pay()
{
Console.WriteLine("어댑터 카드 결제");
}
}
class Program
{
static void Main(string[] args)
{
// 어댑터 패턴 사용 전 코드와 동일
// 기존 클래스를 어댑터 클래스로 변경하여 출력을 변화시킬 수 있음.
Adapter card = new Adapter();
card.Charge();
}
}
}
<참고 사이트>