본문 바로가기

취업/준비

객체지향 / OOP에 대해 설명해보세요

대부분 객체지향 / OOP에 대한 질문을 (준비 없이) 받게 되면

'객체마다 어떤 역할을 부여하고.. 다형성과.. 캡슐화를 통해.. 샬라샬라..'

이렇게 답할테지만, 좀 더 정리해보자. 

 

 

객체지향의 원칙 : SOLID

좋은 객체지향이 뭐라고 생각하냐는 질문에 답하기 좋은 SOLID 원칙을 소개한다.

이 원칙을 잘 지키면 코드의 재사용성과 유지보수성을 키울 수 있다.

그리고 이 원칙을 잘 지키는 각종 디자인 패턴, 소프트웨어 개발론들이 등장하고 있으니 소프트웨어공학에서의 필수 지식이라고 할 수 있다.

 

단일책임원칙 Single responsibility principle

  • 클래스는 단 하나의 책임을 가져야 한다.
    = 클래스를 변경하는 이유가 단 한 개여야 한다.
  • 클래스 안에 여러 책임이 있으면
    • 수정이 잦아진다.
    • 심지어 수정할 경우 다른 기능에 영향이 갈 확률이 높아지기 때문에 유지 보수가 어려워 진다.
    • 기능이 너무 많아 애매해서.. 재사용성도 줄어든다.

 

개방폐쇄 원칙 Open-closed principle

  • 확장에는 개방되어있고, 수정에 있어서는 닫혀있는 구조가 되어야한다는 원칙이다.
  • 새로운 조건이 추가될 때 관련된 다른 객체에 최대한 영향이 없도록 해야한다.
    • 즉, 수정된 클래스 이외에 다른 클래스는 수정하지 않도록 코드를 작성해야한다. 
    • 그러기 위해서는 클래스간의 의존도와 결합도가 작을수록 좋다.
  • 추상화와 다형성을 이용해야 한다.
  • 적용 예시) 전략패턴
    • 새로운 전략 Strategy 을 추가할 때(확장) 서브클래스를 생성해주면 된다.
    • 이 때 Context 클래스에는 영향이 가지 않는다.(폐쇄)
    •  

리스코프 치환원칙 Liskov substitution principle

  • 자식 클래스는 언제나 자신의 부모 클래스로 교체될 수 있다.
  • 즉, 부모 클래스가 들어가는 자리에 자식 클래스를 넣어도 의도에 맞게 작동되야한다.
    • 즉, 업캐스팅을 해도 문제가 되지 않아야한다.
  • 리스코프 치환 원칙은 다형성(상속)과 관련이 깊다.
    • 때문에 리스코프 치환원칙이 잘 지켜져야 개방 폐쇄원칙도 지켜질 수 있다.

인터페이스 분리의 법칙 Interface segregation principle

 클라이언트 입장에서 인터페이스를 분리해야한다!
  • 하나의 클래스가 인터페이스를 여러 개를 왕창 맡아서 구현하면 안된다.
    • 사용하는 것만 맡아서 구현해야 한다.
  • 하나의 인터페이스가 여러 기능을 왕창 갖고 있으면 안된다.
    • 하나의 일반적인 인터페이스보다는 여러 개의 구체적인 인터페이스가 낫다.
  • 단일책임원칙과 마찬가지로 객체가 커지는 것을 막아주는 원칙이라고 볼 수 있다.
    • 객체가 커지는 것을 막아야 하는 이유는 마찬가지로 코드의 변경이 쉬워지기 때문이다.

의존관계역전법칙 Dependency inversion principle

상위 클래스는 하위 클래스에 의존하면 안된다!
  • 의존 관계가 원래 구조와 역전되어, 하위 모듈이 상위 모듈에게 의존해야 한다는 원칙.
  • 클래스에서 하위 클래스가 상위 클래스에 의존하는 것.
  • 인터페이스에서도 마찬가지.
  • 추상화와 관련이 깊다.
    • 추상화(의존관계역전법칙)가 잘 지켜져야 개방 폐쇄 원칙도 잘 지켜질 수 있다.

 

 

객체지향프로그래밍 = OOP

다음으로, 그 객체지향을 어떻게 살려서 프로그래밍에 녹일지. 그걸 위해서 어떤 성질을 지원해야할지 정리해보자.

우선 객체지향 프로그래밍이란,

  • 실세계의 사물을 추상화(Abstraction), 캡슐화(Encapsulation)
  • 계층구조는 상속(Inheritance)
  • 부모와 다른 자식의 특성, 행위는 다형성(Polymorphism)으로 구현

=> 즉, 객체의 구성으로 프로그램을 만들어 가는 것을 객체지향 프로그래밍이라고 한다.

장점

  • 코드의 재사용성 증가
  • 유지보수 비용 감소

구성 요소

객체

  • 클래스의 인스턴스 (엄밀히는 메모리에 할당되고나야 인스턴스)
  • 속성을 갖고 행위를 수행할 수 있다.
  • 객체의 행위는 클래스에 정의된 행위를 공유하여 메모리를 경제적으로 사용한다.

클래스

  • 같은 종류의 집단에 속하는 속성과 행위를 정의한 것.
  • 객체 지향의 기본적인 user define data type
  • 다른 클래스나 외부 요소와는 독립적으로 설계되어 있어야 함.

메소드

  • 한 객체의 서브루틴 형태
  • 객체의 속성을 조작

메시지

  • 수신자와 송신자 객체들 간의 상호작용 수단
  • 다른 객체에 특정 작업을 요청하는 신호를 의미

특징

다형성

  • 하나의 형태가 상황에 따라 여러가지 형태를 가질 수 있는 능력.
  • 오버로딩이나 오버라이딩으로 지원할 수 있다.

오버로딩

  • 하나의 클래스 안에 있는 생성자, 메소드를 재정의 하는 것.
  • 이름은 같지만, 매개변수의 자료형이나 개수가 반드시 달라져야 한다.

오버라이딩

  • 부모 클래스의 메소드를 하위 클래스에서 재정의 하는 것.
  • 상속 관계에 있는 클래스 간의 같은 이름의 메소드를 재정의

상속성

  • IS-A 관계.
  • ex) 부모 클래스 : 사람, 자식 클래스 : 학생, 선생님
    • 학생은 사람이다. (학생 IS A 사람).
    • 선생님은 사람이다. (선생님 IS A 사람).
    • 위와 같은 일반화가 성립되어야 함.
  • 단일 상속
    • 하나의 부모만 상속받을 수 있는 것
  • 다중 상속
    • 여러 부모로부터 상속받을 수 있는 것
  • 반복 상속
    • 같은 조부모 클래스로부터 상속받은 두 부모클래스로부터 상속받는 경우

캡슐화

  • 데이터를 은닉하고 데이터에 접근하는 기능을 제한적으로 운영하는 것
  • 데이터 구조와 데이터를 다루는 방법을 결합시켜 묶는다고 표현할 수도 있음
  • => 데이터를 기능이라는 캡슐로 보호한다.
  • 접근 제한자 사용
    • private : 클래스 내부에서만 접근 가능
    • public : 완전 공개
    • (default) : 같은 패키지에 소속된 클래스에서 접근 가능
    • protected : 같은 패키지와 자식 클래스에서 접근 가능

추상화

  • 공통의 속성이나 기능을 묶어 이름을 붙이는 것

추상 메소드

  • 내용이 없는 메소드
  • body 부분이 없고 선언만 있는 메소드

추상 클래스

  • 한 개 이상의 추상 메소드를 포함하는 클래스
  • 추상 클래스는 객체로 생성될 수 없다.
  • 이를 상속받는 클래스가 추상메소드를 재정의하여 사용한다.

인터페이스

  • 추상메소드와 상수로만 이루어져 있고, 그 외 속성은 가질 수 없음.
  • 물론 최근 JDK에서는 인터페이스 안에서도 default 메소드를 정의할 수 있다.
  • 자바에서 인터페이스로는 다중상속이 가능하다.

 

 

추상 클래스 VS 인터페이스 (JAVA 기준)