만약 Object 가 없고, 또 Object 가 제공하는 toString() 이 없다면 서로 아무 관계가 없는 객체의 정보를 출력하기 어려울 것이다. 여기서 아무 관계가 없다는 것은 공통의 부모가 없다는 뜻이다. 아마도 다음의 BadObjectPrinter 클래스와 같이 각각의 클래스마다 별도의 메서드를 작성해야 할 것이다.
package lang.object.tostring;
public class BadObjectPrinter {
public static void print(Car car) {
String string = "객체 정보 출력: " + car.carInfo(); // carInfo() 메서드 만듦
System.out.println(string);
}
public static void print(Dog dog) {
String string = "객체 정보 출력: " + dog.dogInfo(); // dogInfo() 메서드 만듦
System.out.println(string);
}
}
[ 구체적인 것에 의존 ]
BadObjectPrinter 는 구체적인 타입인 Car, Dog 를 사용한다. 따라서 이후에 출력해야 할 구체적인 클래스가 10개로 늘어나면 구체적인 클래스에 맞추어 메서드도 10개로 계속 늘어나게 된다. 이렇게 BadObjectPrinter 클래스가 구체적인 특정 클래스인 Car, Dog 를 사용하는 것을 BadObjectPrinter 는 Car, Dog 에 의존한다 표현한다.
다행히도 자바에는 객체의 정보를 사용할 때, 다형적 참조 문제를 해결해줄 Object 클래스와 메서드 오버라이딩 문제를 해결해줄 Object.toString() 메서드가 있다. (물론 직접 Object 와 비슷한 공통의 부모 클래스를 만들어서 해결할 수도 있다.)
[ 추상적인 것에 의존 ]
우리가 앞서 만든 ObjectPrinter 클래스는 Car, Dog 같은 구체적인 클래스를 사용하는 것이 아니라, 추상적인 Object 클래스를 사용한다. 이렇게 ObjectPrinter 클래스가 Object 클래스를 사용하는 것을 Object 에 클래스에 의존한다고 표현한다.
package lang.object.tostring;
public class ObjectPrinter {
public static void print(Object object) {
String string = "객체 정보 출력: " + object.toString();
System.out.println(object);
}
}
ObjectPrinter 는 구체적인 것에 의존하는 것이 아니라 추상적인 것에 의존한다.
추상적:여기서 말하는 추상적이라는 뜻은 단순히 추상 클래스나 인터페이스만 뜻하는 것은 아니다. Animal 과 Dog, Cat 의 관계를 떠올려보자. Animal 같은 부모 타입으로 올라갈 수록 개념은 더 추상적이게 되고, Dog, Car 과 같이 하위 타입으로 내려갈 수록 개념은 더 구체적이게 된다.
자바 언어는 객체지향 언어 답게 언어 스스로도 객체지향의 특징을 매우 잘 활용한다.
우리가 지금까지 배운 toString() 메서드와 같이, 자바 언어가 기본으로 제공하는 다양한 메서드들은 개발자가 필요에 따라 오버라이딩해서 사용할 수 있도록 설계되어 있다.
참고 - 정적 의존관계 vs 동적 의존관계