CS_Step10 - 어댑터 패턴(Adapter Pattern)

장선웅·2022년 7월 23일
0

어댑터 패턴?

  • 한 클래스의 인터페이스를 클라이언트에서 사용하고자하는 다른 인터페이스로 변환하는 패턴

다시 말하자면, 호환되지 않는 인터페이슬르 사용하는 클라이언트를 그대로 활용할 수 있으며, 이로써 클라이언트와 구현된 인터페이스를 분리시키며, 이후에 인터페이스가 바뀌더라도 그 변경 내역은 어댑터에 캡슐화 되기 때문에 클라이언트를 바꿀 필요가 없어진다.


1. 어댑터 패턴은 왜 사용할까?

예를 들어, 로봇(Robot)을 만들어보자. 이 로봇의 기능은 왼팔과 오른팔을 위아래로 움직을 수 있다.

//Robot의 팔을 위, 아래롤 움직이게 할 인터페이스 구현
interface ArmMoving{
    //ArmMoving의 추상 메서드 구현(=로봇의 팔을 움직이게 하는 메서드)
    public abstract void up();
    public abstract void down();
}
//Robot의 Arm 객체를 담을 클래스 정의(feat.ArmMoving인터페이스)
 class Arm implements ArmMoving {
    //Arm 생성자 (=Robot의 Arm을 만드는)
    public Arm() {
        System.out.println("Make Robot Arms");
    }
    //ArmMoving 인터페이스를 오버라이딩(=추상 메서드 정의)
    public void up(){
        System.out.println("Robot Arm up");
    }
    public void down(){
        System.out.println("Robot Arm down");
    }
}
//Robot를 구현할 클래스 정의
 class Robot {
    //ArmMoving 인터페이스 변수 설정
    private ArmMoving leftArm; //왼쪽 팔
    private ArmMoving rightArm; //오른쪽 팔
    //Robot 생성자
    public Robot(ArmMoving leftArm,ArmMoving rightArm) {
        this.leftArm = leftArm;
        this.rightArm = rightArm;
    }
    //Robot의 Arm을 움직일 메서드 구현
    public void armUp(){
        rightArm.up();
        leftArm.up();
    }
    public void armDown(){
        rightArm.down();
        leftArm.down();
    }
}
//Client 클래스 구현(main클래스 구현)
public class Cleint {
    public static void main (String[] args){
        //Robot객체 생성
        Robot robot = new Robot(new Arm(),new Arm());
        //Robot의 Arm 움직이기
        robot.armDown();
        robot.armUp();
    }
}
//결과값
Make Robot Arms
Make Robot Arms
Robot Arm down
Robot Arm down
Robot Arm up
Robot Arm up

하지만 여기에서 Robot의 오른 팔을 새로운 팔로 교체해야 한다고 가정하자. 하지만 새로운 팔의 소스는 수정해서는 안된다고 하자. 한 두번 팔을 수정하는 것은 가능하다. 하지만 수정사항이 계속해서 들어온다면, 그때마다 코드를 수정해야하고, 그럴때 마다 코드는 길어진다.


2. 어댑터 패턴 구현 방법

  1. BrandNewArm 클래스 정의
//Robot의 팔을 위, 아래롤 움직이게 할 인터페이스 구현
interface ArmMoving{
    //ArmMoving의 추상 메서드 구현(=로봇의 팔을 움직이게 하는 메서드)
    public abstract void up();
    public abstract void down();
}
//Robot의 Arm 객체를 담을 클래스 정의(feat.ArmMoving인터페이스)
 class Arm implements ArmMoving {
    //Arm 생성자 (=Robot의 Arm을 만드는)
    public Arm() {
        System.out.println("Make Robot Arms");
    }
    //ArmMoving 인터페이스를 오버라이딩(=추상 메서드 정의)
    public void up(){
        System.out.println("Robot Arm up");
    }
    public void down(){
        System.out.println("Robot Arm down");
    }
}
//Robot를 구현할 클래스 정의
 class Robot {
    //ArmMoving 인터페이스 변수 설정
    private ArmMoving leftArm; //왼쪽 팔
    private ArmMoving rightArm; //오른쪽 팔
    //Robot 생성자
    public Robot(ArmMoving leftArm,ArmMoving rightArm) {
        this.leftArm = leftArm;
        this.rightArm = rightArm;
    }
    //Robot의 Arm을 움직일 메서드 구현
    public void armUp(){
        rightArm.up();
        leftArm.up();
    }
    public void armDown(){
        rightArm.down();
        leftArm.down();
    }
}
//BrandNewArm 클래스 정의
class BrandNewArm {
    //BrandNewArm 생성자
    public BrandNewArm() {
        System.out.println("Make Robot BrandNewArm");
    }
    //BrandNewArm을 움직이는 메서드
    public void newUp() {
        System.out.println("Robot BrandNewArm Up");
    }
    public void newDown() {
        System.out.println("Robot BrandNewArm Down");
    }
}
  1. BrandNewArm클래스의 Adapter 클래스 정의
//BrandNewArmAdapter클래스 정의
class BrandNewArmAdapter extends BrandNewArm implements ArmMoving {
    //BrandNewArmAdapter 생성자
    public BrandNewArmAdapter (){}
    //ArmMoving 인터페이스에 있는 추상 메서드 오버라이딩
    public void up(){
        super.newUp();
    }
    public void down(){
        super.newDown();
    }
}
//Client 클래스 구현(main클래스 구현)
public class Main {
    public static void main (String[] args){
        //Robot객체 생성(+ BrandNewArm 붙이기)
        Robot robot = new Robot(new BrandNewArmAdapter(),new Arm());
        //Robot의 Arm 움직이기
        robot.armDown();
        robot.armUp();
    }
}
//결과값
Make Robot Arms
Make Robot BrandNewArm
Robot BrandNewArm Down
Robot Arm down
Robot BrandNewArm Up
Robot Arm up

이렇게 한다면, 기존의 코드 변경 없이, 새로운 팔이 등장한다면, 그에 대한 클래스만 추가하면 된다.


3. 어댑터 패턴의 장/단점

장점

  1. 기존의 코들르 변경할 필요가 없다.
  2. 클래스의 재활용성이 높아진다.

단점

  1. 구성 요소를 위해 클래스를 증가시켜야 하기 때문에 코드가 복잡해질 우려가 잇다
  2. 클래스 어댑테의 경우 상속을 사용하기 때문에 클래스간의 결합도가 높아질 수 있다.
  3. 객체 어댑터의 경우 대부분의 코들를 다시 작성해야하기 때문에 효율적이지 못하다.
profile
개발을 꿈꾸는 초짜

0개의 댓글