[Java] 객체지향프로그래밍과 객체지향의 5원칙 - 코드를 통한 현실 세계 모델링

·2024년 2월 15일
0

Java

목록 보기
3/5
post-thumbnail

객체 지향 프로그래밍

객체 지향 프로그래밍이란 코드를 객체라는 기본 단위로 나누고 이러한 객체를 상호작용하는 방식을 통해, 프로그램의 설계를 진행한다. 객체 지향 프로그래밍은 복잡한 컴퓨터 기술로 현실의 문제를 해결하는데 적합하게 추상화시켜, 설계에 대한 유지보수 및 재사용성에서 강점을 가진 프로그래밍 패러다임이다.

객체 지향 구성요소

  • 클래스 : 특정 객체 내에 변수와 메서드를 정의하는 일종의 추상적인 틀
  • 객체(인스턴스) : 클래스의 인스턴스로, 클래스의 정보를 기반으로 만든 물리적인 요소
  • 속성 : 객체 내 가지고 있는 데이터 값들을 단위별로 정의,
  • 메서드 : 객체 내 데이터를 기반으로 특정 동작을 수행하는 기능 혹은 연산

객체 지향 프로그래밍의 특징

  • 캡슐화 (Encapsulation) : 변수와 함수를 하나의 단위로 묶는 것을 의미한다. 대표적으로 클래스 혹은 프로토타입이 있다. 해당 클래스의 인스턴스를 생성하여, 인스턴스 내부의 변수나 메서드들을 쉽게 사용할 수 있다.

  • 정보은닉(information hiding) : 캡슐화의 추가적인 개념으로, 객체 내 정보에 대해 숨기거나 공개하는 등의 접근 권한을 설정할 수 있다. 접근제한자를 통해 중요한 데이터는 접근하지 못하게 하고, 실제 외부로 공개해야하는 코드만 활용하기 때문에 코드의 보안성이 높아지며, 불필요한 클래스간의 결합을 사전에 미리 방지할 수 있다.

  • 상속 (Inheritance) : 한 클래스가 다른 클래스의 특정을 확장하는 방법으로 부모 클래스의 속성과 메서드를 자식 클래스가 물려받을 수 있다. 이를 통해, 코드의 재사용성이 증가하며, 명확한 계층 구조를 통해, 설계의 가독성 및 유지보수성이 높아진다.

  • 다형성 (Polymorphism) : 동일한 이름의 메서드일지라도 상황에 따라 다양한 특징을 가질 수 있음을 의미한다. A 라는 동작을 메서드에 대해, 이를 그대로 사용하여 A 의 동작을 취하게 할 수도, 재정의를 통해 B , C 라는 동작을 취하는 것이 가능하다. 대표적으로 오버라이딩, 오버로딩이 있다.

    오버라이딩 : 부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 새로운 구현으로 덮어쓰는 것.
    오버로딩 : 같은 이름의 메서드에 대해 다양한 매개변수나 타입을 가지는 것을 허용하여 고유성을 가질 수 있다.

  • 추상화 (Abstraction) : 문제 해결에 필요한 공통적인 요소와 본질을 모아 추출함을 의미한다. 예를들어 자동차와 오토바이 모두 이동 수단을 가지며, 이동 수단은 일반적으로 핸들, 전진, 후진, 브레이크 등의 공통적인 기능을 가진다. 이러한 공통적인 요소를 포함하는 상위적인 명세를 통해 객체를 구현하는 것으로 이동 수단의 본질 요소를 갖춘 객체가 설계되는 것이다. 실무에서의 예시로는 interface 가 있다.

SOLID (객체 지향 설계 원칙)

객체 지향 프로그래밍에서 꼭 지켜야 하는 5개의 원칙을 통틀어, 객체 지향 설계 원칙이라 한다. 5개의 원칙 객체 간의 의존성을 줄이고, 재사용성을 높여 개발 시 유지보수와 확장을 유용하게 하기 위한 특징을 가지고 있다. (이 자체가 객체 지향 프로그램이 가지는 강점이기도 하다)

단일 책임 원칙 (Single Responsibility Principle, SRP)

각 클래스는 오직 하나의 목적을 위해 생성되어야 한다. 클래스가 여러 목적을 가지는 경우, 해당 클래스의 의존도가 높아지며, 구조가 복잡해져, 설계가 어려워질 수 있다.

예를들어, 사칙 연산을 하는 계산 클래스는 오직 계산 기능만 책임을 지므로, 계산 관련 기능에만 명확하게 분업하여 사용되며, 대대적인 수정이 이루어지더라도 영향은 계산 관련 기능에만 미치므로, 불필요한 에러를 예방할 수 있다. 5원칙의 가장 메인이 되는 원칙이며, 남은 4원칙의 근간이 되는 원칙이다.

개방/폐쇄 원칙 (Open/Closed Principle, OCP)

각 클래스는 확장에는 개방적이어야 하고, 수정에는 폐쇄적이어야 한다. 새로운 기능을 추가할 때, 기존의 코드에 영향을 미치지 않으며, 기능을 추가할 수 있도록 하는 것을 의미한다. (클래스간 응집도는 높이며, 결합도는 낮추기 위함)

리스코프 치환 원칙 (Liskov Subsititution Principle, LSP)

자식 클래스는 언제나 부모 클래스로 대체할 수 있어야 함을 의미한다. 즉 부모 클래스가 들어갈 자리에 자식 클래스르 넣어도 정상적으로 프로그램이 작동해야함을 의미한다. 상속의 본질을 중요시 하며, 이를 지키지 않는 경우 부모 클래스 본래의 의미가 변해서 다형성을 보장할 수 없다.

예를 들어, 우리가 컴퓨터에 연결하여 사용하는 마우스는, 어떤 마우스를 컴퓨터에 연결하든 왼쪽 클릭, 휠, 오른쪽 클릭 등을 공통적으로 가지고 있기에 행여 새로운 마우스가 등장하더라도 바로 사용이 가능하다. 그러나 마우스 대신 트랙패드를 사용하는 경우에는 처음 접하는 사람은 평소와 사용방식이 달라, 적응하는데 시간이 필요할 것이다. 이는, LSP 를 잘 지키지 못했다 할 수 있다.

인터페이스 분리 원칙 (Interface Segregation Principle, ISP)

클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 즉 공통사항을 정의하는데 있어, 하나의 큰 인터페이스 보다는, 다수의 구체적인 인터페이스로 나누는 것이 좋다는 것이다.

예를들어 캐릭터 충돌 시 이펙트가 나타나는 액션 게임 기능을 만든다고 가정하자. 이를 하나의 인터페이스로 만들어 처리하는 것도 가능하지만, 이펙트만 나타나야하거나 캐릭터의 충돌만 일어나는 경우가 생긴다면, 불필요한 충돌, 이펙트 데이터를 보내야 하는 문제가 발생한다. 따라서, 충돌과 이펙트를 2개의 인터페이스로 분리한다면 기존의 기능을 그대로 유지하면서도, 위의 문제를 해결할 수 있다.

의존성 역전 원칙 (Dependency Inversion Principle, DIP)

추상성이 높고 안정적인 고수준의 클래스는, 구체적이고 불안정한 저수준의 클래스에 의존해서는 안된다는 원칙이다. 일반적으로 객체지향의 인터페이스를 통해서 이 원칙을 준수할 수 있게 된다.

일반적으로 프로그램 설계 시 클래스는 구현하려는 인터페이스만을 바라보고 구현이 된다. 만약 해당 인터페이스를 가지고 구현한 클래스가 여러개인 경우, 클래스를 교체하더라도, 기존의 코드를 그대로 유지하여 사용하는 것이 가능하다.

예시로는 JPA 의 경우 JDBC Driver 인터페이스를 토대로, MySQL , H2 , MariaDB 등의 다수의 DB Driver 를 가지고 있으며, 만약 서비스에 사용하는 DB 가 변경되는 경우, 기존의 DB Driver 만 변경해주면 기존 구현한 코드 (클라이언트)를 고치지않아도 기능을 그대로 사용할 수 있다. 이는 의존성 역전 원칙을 잘 적용시킨 케이스라고 볼 수 있다.

참고
SOLID 원칙
[OOP] 객체지향 프로그래밍의 5가지 설계 원칙, 실무 코드로 살펴보는 SOLID
객체 지향 프로그래밍의 4가지 특징ㅣ추상화, 상속, 다형성, 캡슐화 -
모듈(Module)이란? 결합도(Coupling)와 응집도(Cohesion)
💠 객체 지향 설계의 5가지 원칙 - S.O.L.I.D

profile
새로운 것에 관심이 많고, 프로젝트 설계 및 최적화를 좋아합니다.

0개의 댓글