캐스팅
캐스팅은 상속 트리 내에서의 객체의 형 변환으로 생각할 수 있다.
업캐스팅은 하위 클래스 객체를 상위 클래스 타입으로 변환하는 것이다. 부모의 관점에서 자식을 바라보는 것으로 이해할 수 있다. 아래와 같이 변수를 생성할 경우, 부모 클래스에서 정의된 속성과 메소드에만 접근할 수 있다. -> 관점
따라서 자식 클래스에서 추가로 정의한 속성과 메소드에는 접근할 수 없다. 업캐스팅은 같은 부모 타입으로 배열을 만들어 여러 자식 객체들을 관리할 수 있어 다형성의 핵심 요소이다. 단, 자식 타입의 참조 변수로 부모 객체를 불러오는 것은 불가능하다.
다운캐스팅은 업캐스팅 된 타입을 다시 자식 클래스 타입으로 변환하는 것이다. 다운캐스티을 통해 자식 클래스에서 정의한 고유 멤버에 접근할 수 있다.
다운캐스팅 시 주의할 점이 2가지 있다. 첫 번째는 업캐스팅 된 타입에만 다운캐스팅이 가능하다는 것이다. 예를 들어 A<-C<-E의 상속 트리에서 E를 A로 업캐스팅했다면, 이를 다시 C 또는 E로 다운캐스팅할 수 있다.
두 번째는 ClassCastException이다. 동물<-강아지, 고양이의 상속 트리에서 강아지를 동물로 업캐스팅했다면, 이를 고양이로 다운캐스팅할 경우 오류가 발생한다. ClassCastException은 런타임 에러로 컴파일 시 잡히지 않기 때문에, instanceOf 연산자로 다운캐스팅이 가능한지 미리 확인하여 오류를 방지해야 한다.


객체 간의 관계(Relationship)
객체 지향 프로그램에서 객체는 다른 객체들과 상호작용한다. -> 서로의 기능을 이용하거나 데이터를 주고 받는다.
주요 관계로는 상속 관계(Is-A), 집합 관계(Has-A), 사용 관계(Use-A)가 있다. 이때 크게 Is-A, Has-A, Use-A 3가지로 나누어 클래스 간의 관계를 구분하는 것이 좋다. 관계가 너무 많아지면 되려 복잡해지고 수정이 번거로워진다.
또한 강한 표현(상속)보다는 약한 표현(합성) 사용을 권장한다. 상속 트리를 구성할 경우 부모 클래스의 영향이 모든 자식 클래스에 미치기 때문에 문제가 발생할 수 있다. 수정이 용이한 유연한 코드를 만들 수 있도록 신경써야 한다.
상속과 구현은 수직적 구조를 형성한다.
Generalization(상속)은 Is-A, Is-Kind-of 관계가 성립할 때만 사용한다. 추상적인 상위 클래스로부터 구체적인 하위 클래스로 이어지는 계층이 형성된다.
JAVA에서는 다중 상속이 허용되지 않는 대신 다중 구현을 허용한다.
Realization(구현)은 Can-Do, Should-Do 관계일 때 사용하며, 객체에 역할, 기능을 부여한다. 객체가 무엇을 할 수 있는가?를 명시하는 것이다. 인터페이스에서 명시한 기능을 하위 클래스에서 구현하지 않으면 오류가 발생한다. 같은 상속 트리가 아닌 객체들도 같은 인터페이스로 연결이 가능하며, 인터페이스 배열으로 묶어 업캐스팅할 수 있다.
합성과 집합은 수평적 구조를 형성한다. 둘 모두 Has-A 관계(소유/포함 관계)이며 객체를 부품화하는 구조를 구현한다. 합성과 집합은 강도에 따라 구분된다.
Composition(합성)은 Strong Has-A 관계일 때 사용한다. 합성 관계인 객체는 생명주기를 함께한다. 예를 들어, 사람을 생성할 때 부분 객체인 심장도 직접 생성한다. 사람이 죽으면 심장도 죽으며, 반대로 심장이 죽어도 사람이 죽는다.
Aggregation(집합)은 Weak Has-A 관계일 때 사용한다. 합성과 달리 포함(전체) 객체가 사라져도 부분 객체가 독립적으로 존재할 수 있다.
연관과 의존 또한 수평적 구조를 형성한다(상속 외 상하 관계 없음).
Association(연관)은 Knows-A 관계일 때 사용하며, 두 객체가 서로 알고 있는 관계이다. 상호 참조(양방향)는 메모리 위험이 있어 주로 한 쪽만 상대를 알고 있도록 한다. 필드를 사용하여 다른 객체를 지속적으로 참조할 수 있도록 한다.
Dependency(의존)은 Use-A 관계일 때 사용하며, 특정 상황에서 다른 객체의 도움을 받는 관계이다. 메소드에서 일시적으로 형성되는 관계이므로 메소드의 인자나 로컬 변수로 구현한다.
SOLID는 객체지향설계의 5가지 핵심원칙을 말한다.
-> 객체지향설계의 궁극적 목적은 유지보수의 편리성, 유연한 확장성, 높은 재사용성이다. -> 수정과 재활용
결합도(Coupling)은 낮을수록 좋다. 모듈과 모듈 간의 의존도를 낮춰 분리/교체하기 편리하도록 설계한다. 응집도(Cohesion)은 높을수록 좋다. 한 모듈 내 구성 요소끼리는 하나의 목적으로 응집되도록 한다.
-> 본질에 충실하도록 구현하여 역할 분리 + 연결
-> if-else로 내부 구현(수정)보다는 interface, 하위 클래스로 확장

