instanceof를 지양하라고요...?

규바·2024년 10월 6일
2
post-thumbnail

어쩌다 instanceof를 지양해야한다는 내용이 포함된 글을 읽었습니다. 왜 쓰지마요...?

instanceof는 다형성을 구현하기 위해 사용하지만, 객체지향적이지 못하기 때문입니다.
따라서 다형성을 더 효과적으로 활용하여 대체하는 것이 이상적인 객체지향 설계라고 볼 수 있다고 합니다.


🖥️ 미리 보는 예시 코드

👎 instanceof 사용 코드

public class ShapePrinter {
    public void print(Shape shape) {
        if (shape instanceof Circle) {
            Circle circle = (Circle) shape;
            System.out.println("원 출력: 반지름 = " + circle.getRadius());
        } else if (shape instanceof Rectangle) {
            Rectangle rectangle = (Rectangle) shape;
            System.out.println("사각형 출력: 가로 = " + rectangle.getWidth() + ", 세로 = " + rectangle.getHeight());
        }
    }
}

public interface Shape {
    // ...
}

public class Circle implements Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    public double getRadius() {
        return radius;
    }
}

public class Rectangle implements Shape {
    private double width;
    private double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    public double getWidth() {
        return width;
    }
    
    public double getHeight() {
        return height;
    }
}

👍 다형성 활용

public class ShapePrinter {
    public void print(Shape shape) {
        shape.print();
    }
}

public interface Shape {
    void print();
}

public class Circle implements Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public void print() {
        System.out.println("원 출력: 반지름 = " + radius);
    }
}

public class Rectangle implements Shape {
    private double width;
    private double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public void print() {
        System.out.println("사각형 출력: 가로 = " + width + ", 세로 = " + height);
    }
}

🚫 객체지향 원칙에 위배

📍 캡슐화 깨짐

캡슐화: 데이터와 그 데이터를 조작하는 메서드를 하나의 단위로 묶고, 객체의 내부 구현을 외부로부터 숨기는 것

instanceof 코드에서의 문제점
ShapePrinter 클래스가 shape 매개변수가 어떤 객체인지 알게됩니다. 더불어CircleRectangle의 내부 구조(반지름, 가로, 세로)를 직접 알고 있습니다.

다형성을 활용한 코드에서는 추상화된 shape를 잘 활용해서 외부의 객체(ShapePrinter)가 불필요한 정보를 알지 않게 해주고 있습니다.

📍 OCP

OCP : 확장에는 개방되어 있어야 하고 수정에는 폐쇄되어야 한다는 원칙, 새로운 기능이 추가되더라도 기존 코드를 수정하지 않고 확장할 수 있어야 한다.

만약 새로운 도형(객체)를 추가하고 싶다면 다형성 활용 코드에는 아래처럼 객체를 추가해주기만 하면 될 것입니다.

public class Triangle implements Shape {
    private double base;
    private double height;
    
    public Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }
    
    @Override
    public void print() {
        System.out.println("삼각형 처리: 밑변 = " + base + ", 높이 = " + height);
    }
}

instanceof를 사용하는 코드의 경우 아래처럼 조건문을 붙여줘야 했을 것입니다.

 else if (shape instanceof Triangle) {
            // ...
        }

지금은 하나의 객체가 추가되고, 하나의 메서드만 수정사항일 뿐이지만...

도형을 체크하는 메서드가 1000개 있고
또 도형이 1000개 추가되어야 한다면 모든 instanceof를 사용하는 곳의 조건을 추가해야 할 것입니다. 유지보수가 엄청 어려울 것 같습니다. OCP를 위반했다고 볼 수 있습니다.

Triangle 객체를 처리하는 코드를 잘 추가하지 않으면 동작하지 않으니 LSP를 위반했기도 하네요...

📍 SRP

SRP : 하나의 객체는 반드시 하나의 기능만을 수행하는 책임을 갖는다는 원칙

instanceof 방식에서는
ShapeProcessor가 모든 도형 타입의 처리 방식을 알고 있어야합니다. 여러 가지 책임(각 도형들의 프린트)을 지고 있는 것 입니다. SRP를 위반했다고 볼 수 있습니다.

다형성 활용 코드에서는
그냥 shape.print()호출에 대한 책임만을 지고 있네용
각 도형의 프린트는 각 도형 클래스가 책임을 알아서 지고 있습니다.


💭 마무리

특정 자료형의 타입을 판별하는 경우 필연적으로 instanceof를 사용해야 할 수도 있습니다. 그러나 좋은 코드 설계에서는 instanceof 사용을 피하는 것이 좋다고 합니다.

객체지향은 어려운데 또 신기하고 재밌는데 어려운 것 같아요 끝이없는 듯



관련 내용 검색해보니까 전부 우테코 미션이던데, instanceof를 지양하라는 가이드가 우테코에 있나보네요.

참고

profile
그때그때 학습하고 있는 내용을 올려요

1개의 댓글

comment-user-thumbnail
2024년 10월 8일

좋은글 감사합니잇~

답글 달기