7월 4일 - 어뎁터 패턴

Yullgiii·2024년 7월 4일
0
post-thumbnail

어댑터 패턴

용도

어댑터 패턴은 클래스를 바로 사용할 수 없는 경우에 유용하다. 예를 들어, 다른 곳에서 개발되었거나 수정할 수 없는 클래스를 사용할 때, 중간에서 변환 역할을 해주는 클래스가 필요하다. 어댑터 패턴은 이런 상황에서 호환되지 않은 인터페이스를 사용하는 클라이언트를 그대로 활용할 수 있게 해준다. 또한, 향후 인터페이스가 바뀌더라도 변경 내역은 어댑터에 캡슐화되므로 클라이언트 코드를 변경할 필요가 없다.

클래스 다이어그램

예제 설명

아이폰의 이어폰을 생각해보자. 일반적인 이어폰 잭을 아이폰에 사용하려면, 잭 자체가 맞지 않는다. 따라서 우리는 어댑터를 따로 구매해서 연결해야 이런 이어폰들을 사용할 수 있다. 이처럼 어댑터는 필요로 하는 인터페이스로 바꿔주는 역할을 한다.

이처럼 업체에서 제공한 클래스가 기존 시스템에 맞지 않으면, 기존 시스템을 수정할 것이 아니라 어댑터를 활용해 유연하게 해결할 수 있다.

코드로 어댑터 패턴 이해하기

자동차와 보트 인터페이스 생성

만약 자동차 객체가 부족해서 보트 객체를 대신 사용해야 한다면, 두 객체는 인터페이스가 다르므로 바로 보트 객체를 사용하는 것은 불가능하다. 따라서 보트 어댑터를 생성해서 활용해야 한다.

Car.java

package AdapterPattern;

public interface Car {
    public void drive();
    public void honk();
}
  • Car 인터페이스는 drivehonk 메서드를 정의하고 있다. 이는 자동차의 기능을 나타낸다.

Boat.java

package AdapterPattern;

public interface Boat {
    public void sail();
    public void soundHorn();
}
  • Boat 인터페이스는 sail과 soundHorn 메서드를 정의하고 있다. 이는 보트의 기능을 나타낸다.

SpeedBoat.java

package AdapterPattern;

public class SpeedBoat implements Boat {
    @Override
    public void sail() {
        System.out.println("The boat is sailing");
    }

    @Override
    public void soundHorn() {
        System.out.println("Boat horn sounds");
    }
}
  • SpeedBoat 클래스는 Boat 인터페이스를 구현하며, sailsoundHorn 메서드를 오버라이드하여 실제 보트의 동작을 정의하고 있다.

BoatAdapter.java

package AdapterPattern;

public class BoatAdapter implements Car {
    Boat boat;

    public BoatAdapter(Boat boat) {
        this.boat = boat;
    }

    @Override
    public void drive() {
        boat.sail();
    }

    @Override
    public void honk() {
        boat.soundHorn();
    }
}
  • BoatAdapter 클래스는 Car 인터페이스를 구현하며, Boat 객체를 인스턴스 변수로 가진다.
  • drive 메서드는 boat.sail()을 호출하여 보트의 sail 메서드를 실행하고, honk 메서드는 boat.soundHorn()을 호출하여 보트의 soundHorn 메서드를 실행한다.
  • 이 어댑터를 통해 Boat 객체를 Car 객체처럼 사용할 수 있게 된다.

AdapterTest.java

package AdapterPattern;

public class AdapterTest {
    public static void main(String[] args) {
        SportsCar car = new SportsCar();
        SpeedBoat boat = new SpeedBoat();
        Car boatAdapter = new BoatAdapter(boat);

        System.out.println("The boat says...");
        boat.sail();
        boat.soundHorn();

        System.out.println("The Car says...");
        testCar(car);

        System.out.println("The BoatAdapter says...");
        testCar(boatAdapter);
    }

    public static void testCar(Car car) {
        car.drive();
        car.honk();
    }
}
  • AdapterTest 클래스는 main 메서드를 통해 어댑터 패턴을 테스트한다.
  • SportsCar 객체와 SpeedBoat 객체를 생성하고, SpeedBoat 객체를 BoatAdapter로 감싸 Car 인터페이스로 변환한다.
  • testCar 메서드는 Car 인터페이스를 인자로 받아 drivehonk 메서드를 호출한다.
  • 이를 통해 어댑터가 Car 인터페이스를 구현함으로써, SpeedBoat 객체를 Car 객체처럼 사용할 수 있음을 보여준다.

So...

어댑터 패턴은 호환되지 않은 인터페이스를 사용하는 클래스를 변환하여 클라이언트가 사용할 수 있도록 해준다. 이를 통해 기존 시스템을 수정하지 않고도 새로운 클래스를 유연하게 통합할 수 있다. 어댑터 패턴은 특히 변경 가능한 인터페이스가 있을 때 유용하며, 클라이언트 코드의 안정성을 유지하면서도 다양한 클래스와의 통합을 가능하게 한다.

profile
개발이란 무엇인가..를 공부하는 거북이의 성장일기 🐢

0개의 댓글