diff --git "a/\352\265\254\354\241\260/4\354\243\274\354\260\250-\354\226\264\353\214\221\355\204\260/example-code.md" "b/\352\265\254\354\241\260/4\354\243\274\354\260\250-\354\226\264\353\214\221\355\204\260/example-code.md" new file mode 100644 index 0000000..34e3e19 --- /dev/null +++ "b/\352\265\254\354\241\260/4\354\243\274\354\260\250-\354\226\264\353\214\221\355\204\260/example-code.md" @@ -0,0 +1,142 @@ +## 1. 어댑터 패턴(Adapter Pattern) 이란? + +어댑터 패턴은 **기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴**을 말한다. + +일반적으로 어댑터 패턴은 110V 콘센트와 220V콘센트를 변환해주는 것을 예로 많이 든다다. 해당 예시를 개발 관점으로 얘기하자면, 클라이언트가 사용하는 인터페이스가 기존 코드와 다를 때, **기존 코드를 클라이언트 코드와 호환될 수 있게 처리해 주는 것으로 생각**하면 된다. + +![adapter](https://user-images.githubusercontent.com/79291114/160358256-30481999-0b13-425b-90e3-ffac32e6f843.PNG) + +- `Target` : `Client`가 사용하는 인터페이스 +- `Adaptee` : 기존에 사용하던 코드 +- `Adapter` : `Client`에서 `Adaptee`를 사용하기 위해 `Target`으로 변환 시켜 줌 + +결국 핵심은 **Adapter를 이용해 Adaptee를 Target으로 변환**해 준다는 것이다. + + + + + +## 2. 어댑터 패턴적용 예제 + +### 2-1. 요구사항 + +메일 발송을 위해 `솔루션 회사 A`와 계약하여 발송 프로세스를 개발하여 사용하고 있는데, `솔루션 회사 B`와 계약하여 메일을 발송하고 싶은 요구사항이 있다. + +현재 서비스 되고 있는 많은 부분을 변경하는 것은 위험하기 때문에, `솔루션 회사 A` 인터페이스를 사용한 수많은 클래스와 데이터들을 유지하면서 `솔루션 B`를 적용하고 싶다. + +그래서, 서로 다른 **A사와 B사의 인터페이스를 함께 동작시킬 수 있도록 개발**했으면 한다. + + + +### 2-2. Adapter 패턴 적용하기 + +솔루션 회사 A의 인터페이스는 아래와 같다. + +```java +// 솔루션 회사 A 인터페이스 +public interface MailSenderA { + void send(String sendInfo); +} + +// 기존에 구현되어있는 메일 발송 로직 +public class SolutionA implements MailSenderA { + + @Override + public void send(String sendInfo) { + System.out.println("A 솔루션 회사에서 메일 발송 : " + sendInfo); + } +} +``` + +당연하겠지만, 솔루션 회사 B는 인터페이스 규격이 회사 A와 다르다. + +```java +// 솔루션 회사 B 인터페이스 +public interface MailSenderB { + void sendApi(String sendInfo); +} + +// To-Be 메일 발송 로직 +public class SolutionB implements MailSenderB { + + @Override + public void sendApi(String sendInfo) { + System.out.println("B 솔루션 회사에서 메일 발송 : " + sendInfo); + } +} +``` + +여기에 클라이언트 입장에서 솔루션 회사 B를 범용성있게 적용하기 위해 `Adapter 패턴`을 활용할 수 있다. + +![adapter.png](https://user-images.githubusercontent.com/42997924/159971038-0e4cea2f-ebcc-46f7-b44c-441f746443af.png) + +```java +// Adapter Class +public class Adapter implements MailSenderA { + + // Adaptee(B회사) 생성자 주입 + private final MailSenderB mailSenderB; + + public Adapter(SolutionB newSolution) { + this.mailSenderB = newSolution; + } + + @Override + public void send(String sendInfo) { + System.out.print("Using Adapter >>> "); + // 기존 send를 호출 -> 솔루션 B의 sendApi 호출 연결 + mailSenderB.sendApi(sendInfo); + } +} +``` + +클라이언트는 기존에 사용하던 인터페이스 그대로 활용할 수 있게 됐다. + +```java +// 클라이언트 코드 +public class Client { + public static void main(String[] args) { + + MailSenderA senderA = new SolutionA(); + senderA.send("기존 발송 메일"); + + senderA = new Adapter(new SolutionB()); + senderA.send("TO-BE 발송 메일"); + } +} + +/* 실행 결과 +A 솔루션 회사에서 메일 발송 : 기존 발송 메일 +Using Adapter >>> B 솔루션 회사에서 메일 발송 : TO-BE 발송 메일 +*/ +``` + +> 기존에 있는 시스템(솔루션 A 활용)의 레거시 인터페이스를 새로운 인터페이스(솔루션 B)로 교체하는 경우에 기존 코드를 수정하지 않고 재사용성을 높일 수 있다. 새로운 써드파티 라이브러리가 추가되어도 어댑터 패턴은 유용하게 사용된다! + + + + + +## 3. 장/단점 + +### 장점 + +- 기존 코드(Adaptee)를 변경하지 않고 원하는 인터페이스(Target) 구현체를 만들어 재사용할 수 있다. + - 기존 코드를 변경하지 않고, 확장할 수 있다는 점에서 `OCP(Open Closed Principle)` 원칙에 가까운 패턴이다. +- 기존 코드가 하던 일과 특정 인터페이스 구현체로 변환하는 작업을 각기 다른 클래스로 분리하여 관리할 수 있다. + - 각각 하던 일에 집중할 수 있기 때문에 `SRP(Single Responsibility Principle)` 원칙에 가까운 패턴이다 + + + +### 단점 + +- 클래스가 많아지고 구조가 복잡해진다. + - 경우에 따라서는 기존 코드가 해당 인터페이스를 구현하도록 수정하는 것이 좋은 선택이 될 수도 있다. + + + + + +## 4. 마치며 + +사람인 데이터와 같이 다양한 데이터들이 얽혀있는 경우 기존 코드에 영향이 가지 않는 어댑터 패턴을 고려하는 것도 좋아보인다. \ No newline at end of file