어쩌다 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
매개변수가 어떤 객체인지 알게됩니다. 더불어Circle
과 Rectangle
의 내부 구조(반지름, 가로, 세로)를 직접 알고 있습니다.
다형성을 활용한 코드에서는 추상화된 shape를 잘 활용해서 외부의 객체(ShapePrinter
)가 불필요한 정보를 알지 않게 해주고 있습니다.
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 : 하나의 객체는 반드시 하나의 기능만을 수행하는 책임을 갖는다는 원칙
instanceof 방식에서는
ShapeProcessor
가 모든 도형 타입의 처리 방식을 알고 있어야합니다. 여러 가지 책임(각 도형들의 프린트)을 지고 있는 것 입니다. SRP를 위반했다고 볼 수 있습니다.
다형성 활용 코드에서는
그냥 shape.print()
호출에 대한 책임만을 지고 있네용
각 도형의 프린트는 각 도형 클래스가 책임을 알아서 지고 있습니다.
특정 자료형의 타입을 판별하는 경우 필연적으로 instanceof를 사용해야 할 수도 있습니다. 그러나 좋은 코드 설계에서는 instanceof 사용을 피하는 것이 좋다고 합니다.
객체지향은 어려운데 또 신기하고 재밌는데 어려운 것 같아요 끝이없는 듯
관련 내용 검색해보니까 전부 우테코 미션이던데, instanceof를 지양하라는 가이드가 우테코에 있나보네요.
참고
좋은글 감사합니잇~