새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.

1 분 소요

오늘은 객체 지향 프로그래밍에 대해서 전체적으로 훑어보는 시간이였습니다.

자바에서 인터페이스와 추상 클래스는 추상화를 제공합니다.

추상화란 객체 간 상호작용 시, 실제 구현체의 메서드를 직접 호출하지 않고, 인터페이스나 추상 클래스의 추상 메서드를 호출하여 이를 구현 메서드를 사용하는 방식을 말합니다.

이런 추상화는 키워드로 정리하면 다음과 같습니다.

  • 구현체에 대한 의존성 제거

    호출하는 객체는 특정 구현체를 의존하지 않으므로, 구현체를 변경하거나 확장하기 용이합니다.

  • 유연성 증가

    동일한 인터페이스나 추상 클래스를 구현한 다양한 객체들을 사용할 수 있어 코드의 유연성과 재사용성이 높아집니다.

  • 유지보수 용이

    추상화를 통해 구현체 변경이 필요한 경우 인터페이스나 추상 클래스의 메서드 시그니처를 유지하면서 구현체만 수정하면 되므로 유지보수가 용이합니다.

추상 클래스와 인터페이스는 동일한 추상 메서드를 제공하는데 가장 큰 차이점은 “상태”가 전이되는 유무입니다.

  • 추상 클래스는 상태(필드)를 가질 수 있으며, 상속을 통해 이를 하위 클래스에 전이할 수 있습니다.
  • 인터페이스는 상태를 가지지 않으며, 구현을 통해 추상화를 제공합니다.

상속은 상위 클래스의 속성과 행위를 그대로 하위 클래스에게 전이합니다.

상위 클래스가 변경되면 하위 클래스에 영향을 미치게 되고, 코드를 수정할 수도 있습니다.

이렇게 클래스끼리 영향을 끼치게 되는 것을 결합도가 강하다고 합니다.

결합도가 강하다는 것은 객체 지향 프로그래밍의 장점이 사라질 수 있습니다. 객체 지향의 장점은 확장에 자유롭고, 유지보수하기 편하며, 캡슐화를 통해 재사용하기 좋다는 것입니다. 하지만 강한 결합으로 인해 클래스간 영향이 발생하여 확장할 때마다 다른 클래스도 수정이 발생할 수 있기 때문에 확장이 여려워집니다. 테스트 코드를 작성하는 범위도 상위 클래스에서 하위 클래스까지 진행해야하는 어려움도 발생합니다.

객체 지향 프로그래밍에서 캡슐화를 통해 정보 은닉과 데이터 오염을 방지할 수 있습니다. 다만 멀티 쓰레드 환경에서는 내부 필드를 추상화를 통해 수정이 가능하게 된다면 race condition이 발생할 수 있습니다. 추가로 코드가 길어지게 된다면 처음 사용한 객체와 마지막 객체의 상태가 다를 수 있기 때문에 객체를 수정하는 로직이 있다면 해당 로직을 봐야하는 일이 생깁니다. 이는 캡슐화가 깨지게 되는 것이며 이를 방지하고자 불변 객체를 사용합니다.

불변 객체를 사용하는 이유는 불변 상태라는 점입니다.

메서드로 상태를 변경할 경우 새 인스턴스가 반환되는 방식으로 속성을 변경후 오류가 발생하여도 원본 객체는 변경되지 않았기 때문에 원시성을 유지할 수 있습니다. 또한 hashCode자료 구조를 사용하는 컬렉션에서도 오류가 발생하지 않습니다.

여기서 말하는 오류란 객체를 자료구조에 저장하고 속성을 수정하는 경우 데이터를 찾을 때 hashCode의 결과가 다르기 때문에 오류가 발생하는 것을 말합니다. 속성이 불변하기 때문에 이런 오류를 방지할 수 있으며 가비지 컬렉션의 성능을 높일 수 있습니다.

성능을 높아지는 이유는 불변 객체는 참조 추적을 쉽게 식별할 수 있기 때문입니다.

이런 이유로 불변 객체를 사용하게 되는데 추상 클래스는 다른 객체에 전달될 때 가변 객체로 전달 될 수 있기 때문에 불안전하며

상태를 예측할 수 없습니다. 가변 객체로 전달될 수 있다는 의미는 현재는 불변 객체일지라도 상위 클래스의 변경으로 인해 불변 객체가 깨질수 있기 때문입니다.

댓글남기기