Skip to content

Object-Oriented Programming (OOP) Fundamentals

예전의 절차 지향 프로그래밍 방식으로는 데이터가 기하급수적으로 늘어나고 있는 상황에 대처하기가 힘들어져서 나온 프로그래밍 방식.

핵심 개념

  1. 추상화

    현실 세계에서 특정한 대상을 관찰하여 핵심적이고 특징적인 공통점들을 뽑아내는 과정.

    프로그래밍에 필요한 데이터만 추려내서 속성과 행위로 나누어 캡슐화를 하는데, 그렇게 하나로 묶어서 만들때 사용하는 개념적인 주체가 클래스이다.

    객체는 그렇게 클래스라는 개념으로 정의되어진 존재에서 비롯된 실체화된 것이다.

    이렇게 보면 클래스는 붕어빵 틀이고 객체는 붕어빵 틀에서 찍혀나온 붕어빵 자체라고 할수도 있겠다.

  2. 캡슐화

    캡슐화란 속성과 행위들을 관련있는 것끼리 묶는 것이다.

    이때 외부에서 접근이 필요한 부분을 제외하고는 은닉해야 하는 점이 가장 중요하다.

    정보 은닉의 목적은 클래스 내부 구현의 응집도를 높이고 외부 다른 클래스와의 결합도를 낮추는데 있다.

    때문에 일반적인 객제지향 언어에서는 public이라든가 private 같은 접근제한자 문법을 지원한다.(ex. JAVA)

  3. 상속

    상속은 객체지향의 핵심 기능 중 하나로 대상이 되는 클래스의 모든 특징들을 물려 받는 것을 말한다.

    예를 들면 파충류라는 부모 클래스 밑에 악어, 도마뱀 같은 자식 클래스가 존재하는 구조랄까. 악어, 도마뱀 같은 자식 클래스들은 파충류라는 부모 클래스의 속성들을 물려받는 구조이다.

    어떤 클래스를 이미 상속 받은 클래스를 다시 다른 클래스가 상속 받을 수도 있는데 위의 예를 이어가자면 파충류라는 클래스를 상속받은 악어 클래스에서 엘리게이터, 크로커다일 등으로, 도마뱀에서 카멜레온, 이구아나 등으로 표현 할 수 있겠다.

    이렇게 상속의 상속을 이어가다 보면 클래스 간의 관계가 계층형 구조를 형성하게 되는대, 이런 형태의 관계에서 아래로 내려갈수록 구체화 된다고 하고 위로 올라갈수록 일반화 된다고 표현한다.

    위의 구조에서 보다시피 구체화 될수록 고유의 특징들이 더 많이 생겨나게 되고 일반화 될 수록 더 많은 객체(클래스)에 영향을 주게 된다.

    부모 클래스의 특징들을 물려받게 되면 이미 구현된 세부 내용을 자식 클래스에서 다시 구현할 필요가 없기 때문에 코드의 재사용성이 향상된다.

    하지만 코드의 재사용성만을 고려하여 상속 관계를 형성하다 보면 자칫하면 다 꼬여버릴수 있기 때문에 주의가 필요하다.

    상속 관계가 성립하려면 두 클래스 간의 관계가 is-a 관계여야 한다. is-a란 ~은 ~이다 라고 할수 있는 관계이다.(예를 들면 악어는 파충류이다.)

    즉, 자식 클래스가 들어간 문장이 있을 때 자식 클래스를 부모 클래스로 대체해도 의미가 성립되야 한다.

    • 악어는 파충류이다.
    • 엘리게이터는 악어이다.
    • 도마뱀은 파충류이다.
    • 이구아나는 도마뱀이다.

    이렇게 의미가 다 성립이 되어야 제대로 된 상속 관계라고 볼 수 있다.

    is-a가 아닌 has-a 관계로 클래스간의 관계를 형성하는 실수가 많은데,

    has-a 관계란 악어-비늘, 새-날개 등 하나의 클래스가 다른 클래스의 일부로 속할 때 has-a 관계라고 한다.

  4. 다형성

    객체지향에서 다형성이란 하나의 속성이나 행위가 상황에 따라 다른 의미로 해석될 수 있는 특징을 말한다.

    다형성을 구현하는 대표적인 방법으로는 위에서 다룬 상속을 이용하는 것이 있다.

    상위 클래스의 메소드를 하위 클래스에서 재정의(override)하여 상위 클래스의 참조변수가 어떠한 하위 클래스의 인스턴스를 참조하느냐에 따라 동작이 달라지는 개념으로 이러한 방식으로 구현되는 다형성을 서브타입 다형성이라고 한다.

    예를 들어 이동이라는 행위가 있을때 이동이라는 행위는 실제 이동이라는 행위를 수행하는 대상에 따라서 방식이 달라진다.

    네발로 기어간다든가 두발로 뛰어간다든가 하는 식으로 말이다.

    이 이동 동작을 객체지향이 아닌 절차지향으로 표현하려면 if 조건으로 각각의 대상을 확인하고 대상마다 행위를 정의하는 식으로 하겠지만 객체지향에서는 부모 클래스의 이동이라는 method를 자식 클래스에서 재정의하면 같은 명령어로 각각 다른 동작을 수행하게 할 수 있다.

    이렇게 비즈니스 로직을 일반화된 코드로 구현해놓으면 요구사항이 변경되어 코드를 수정해야 하는 경우에 일반화된 코드는 건드리지 않고 하위 클래스의 method만 수정하거나 클래스를 추가 구현하는 것으로 해결 할 수 있다.

    그리고 코드의 가독성이 높아지고 일관성이 생기기 때문에 개발자의 실수를 줄일 수 있겠다.

객체지향 프로그래밍 5원칙(S.O.L.I.D)

위의 개념들을 적용시켜서 정리한 객체지향 프로그래밍의 5원칙이 있다.

  1. SRP(Single Responsibility Principle) : 단일 책임 원칙

    클래스는 단 하나의 책임을 가져야 하며 클래스를 변경하는 이유는 단 하나의 이유이어야 한다.

  2. OCP(Open-Closed Principle) : 개방-폐쇄 원칙

    확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.

  3. LSP(Liskov Substitution Principle) : 리스코프 치환 원칙

    상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.

  4. ISP(Interface Segregation Principle) : 인터페이스 분리 원칙

    인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.

  5. DIP(Dependency Inversion Principle) : 의존 역전 원칙

    고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.

참고 블로그 : https://gracefulprograming.tistory.com/130

IronTrain Tech Blog