메이쁘

[SW CS] 객체 지향 프로그래밍(OOP : Object-Oriented Programming) 은 무엇일까? (feat.절차적 프로그래밍) 본문

면접 대비 CS지식/else

[SW CS] 객체 지향 프로그래밍(OOP : Object-Oriented Programming) 은 무엇일까? (feat.절차적 프로그래밍)

메이쁘 2020. 9. 6. 19:42

안녕하세요.

 

Java 하면 생각나는 것인 객체 지향 프로그래밍.

 

이에 대해 정리해보는 시간을 가지려고 포스팅하게 되었습니다.

 

 

 

 

객체 지향 프로그래밍?


C언어 : 절차적 프로그래밍(POP) <-> Java : 객체 지향적인 프로그래밍(OOP)

 

이렇게 나뉩니다.

 

 

뜻은 말과 똑같이,

절차적 프로그래밍은 실행 절차(순서) + 프로시저(메소드, 함수, 루틴 등)의 사용 을 더 중요시하는 것 이고

객체 지향 프로그래밍은 객체들의 종류와 속성(형태) 를 더 중요시하는 것 입니다.

 

C언어가 절차적 프로그래밍이라고 했는데,

컴퓨터의 작업 처리 방식은 위에서 아래(순차적)로 실행되는데 컴퓨터 내부 구조나 OS가 보통 C언어로 만들어져있습니다.

 

옛날옛적에야 단순히 연산 작업을 하는 소프트웨어 같이 규모가 크지 않은 소프트웨어를 처리했기 때문에 절차적 프로그래밍 방식으로도 정상 작동시킬수 있었지만, 하드웨어의 발달보다 소프트웨어의 발달이 급격히 커지면서 단순 연산 작업이 아닌 고도의 작업까지 처리하는 소프트웨어들이 나오기 시작했습니다.

그만큼 코드량이 방대해지고, 이에 따라 유지 / 관리가 어려워지기 시작했습니다.

뿐만 아니라, 소프트웨어 언어 및 컴파일러 또한 발달하면서 하드웨어 처리가 못따라가는 상황도 발생했습니다.

 

그래서 안되겠다! 프로그래밍 방식을 바꿔보자. 해서 나오게 된게 객체지향 프로그래밍 입니다.

 

 

중간정리

절차적 프로그래밍

  ->  실행 절차 + 단순 프로시저 사용을 중요시하는 프로그래밍.

  ->  대표적인 절차적 프로그래밍 언어는 C언어.

 

 

장점

  ->  컴퓨터의 처리구조 방식과 유사하여 실행 속도가 빠르다.

 

단점

  ->  유지보수가 어렵다. (Oh, my 스파게티 코드!)

  ->  디버깅이 어렵다.

  ->  실행 순서가 바뀌면 같은 결과가 나오지 않을 수 있다.

 

 

 

 

그럼 이제, 객체 지향 프로그래밍에 대해 알아보겠습니다.

그전에 객체에 대해 짚어보자면,

 

객체 : 하나의 역할을 수행하는 메소드와 변수(데이터)의 묶음 (자바에선 class, public 등 이 있음)

 

그럼, 객체 지향 프로그래밍은

여러 프로그램(기능) 들을 '객체' 라는 기본 단위로 쪼개서 구현하고, 이러한 객체들의 상호작용으로 프로그래밍 하는 방식

 

입니다.

 

좀 더 자세하게는, 작은 문제들을 해결하는 기능들을 객체로 만든 후, 이러한 객체들을 어찌저찌 잘 조합해가면서 큰 문제를 해결하는 상향식(Bottom-up) 방식 의 프로그래밍 입니다.

그렇기 때문에, 재사용성이 늘어나 코드의 유지보수가 대폭 개선되었으며, 이는 곧 개발 시간과 비용을 줄이는 효과를 불러왔습니다.

 

 

이러한 역사와 흐름대로 객체 지향 프로그래밍이 주목받고, 으뜸으로 서게 되었습니다.

 

 

 

중간정리

객체 지향 프로그래밍

  ->  객체 중심적 프로그래밍. 즉, 여러 작은 기능들을 객체로 만들고, 이러한 객체들의 상호작용으로 프로그래밍하는 방식

  ->  대표적인 객체 지향 프로그래밍 언어로 Java가 있음.

  ->  객체 지향 프로그래밍이라고 절차적인 방식(순차적인 실행) 이 아닌건 아닙니다. 순차적으로 실행되는데, 중점적인 부분이 다를 뿐입니다. (프로시저 vs 객체)

 

 

장점

  ->  코드 재사용이 쉽다.

  ->  이는 곧 유지보수가 쉽다는 말. 보통 객체는 클래스 단위로 생성하기 때문에, 클래스 내부 멤버 변수 또는 함수를 수정하면 호출 프로시저 하나하나 건드리지 않고도 기능 변경이 가능하다.

  ->  프로젝트의 규모가 커질수록 개발에 용이하다. 객체 단위로 모듈화시켜서 개발하기 때문에, 여러 명이 각자의 기능을 개발해도 다른 사람의 기능을 건드리지 않게 되고, 각자의 객체를 합쳐서 사용하기 편하기 때문이다. (강한 응집력 / 약한 결합력)

 

단점

  ->  처리속도가 절차적 프로그래밍보다는 상대적으로 느리다. (하지만 효율적인 처리는 가능하지.)

  ->  설계할 때 많은 시간을 소요할 수 있다. 작은 문제들까지 최대한 많이 나눠야하고, 이러한 문제 하나하나 객체로 만들어야 하니까.

 

 

 

그럼 이제, 객체 지향 프로그래밍의 특징을 알아보겠습니다.

 

 

객체 지향 프로그래밍 4대 특징


 캡슐화 (Encapsulation)

  -  "외부에서는 객체가 어떤 메소드와 멤버 변수로 구성되어 있고, 어떻게 일처리하는지 몰라도 된다."

  -  변수와 함수를 하나의 단위(보통 클래스) 로 묶는 것.

  -  이에 더해, 멤버 변수를 private로 두고 getter/setter 사용하는 방식인 정보 은닉(Information Hiding) 이 보조개념으로 존재하는데, 보통 합쳐서 캡슐화라고 합니다.

  -  외부에서 잘못된 사용으로 인해 객체가 손상되거나 변경되는 것을 막기 위해 사용

 

 

상속(Inheritance)

  -  자식 클래스가 부모 클래스의 특성과 기능을 물려받을 수 있고, 이를 확장할 수 있다.

  -  extends 키워드.

  -  코드의 중복을 없애기 위해 사용된다.

 

 

다형성(Polymorphism)

  -  상속을 통해 기능을 확장하거나 변경하는 것이 가능한 것.

  -  부모 클래스와 자식 클래스가 이름은 동일하지만, 각각 다르게 일을 처리할 수 있다.

  -  그냥 쉽게 말하면, 형태는 같은데 여러 다른 역할을 할 수 있는 것 이다.

  -  OverridingOverroding이 있음

 

Overriding

  -  부모 클래스를 상속받은 자식 클래스에서 부모 클래스의 메서드를 자식 클래스에서 원하는대로 다시 재정의해서 사용하는 것

class A {
  public int getA() {
    return 1;
  }
}

class B extends A {
  @Override
  public int getA() {
    return 2;
  }
}

class Main {
  public static void main(String args[]) {
    B b = new B();
    A a = new A();
    
    a.getA();  // 1 리턴
    b.getA();  // 2 리턴
  }
}

  -  같은 함수 이름인 getA 가 class B(자식 클래스) 에서 재정의했고, 부모 클래스와 자식 클래스의 함수를 호출하면 각각 리턴 값이 다르다.

 

 

Overroding

  -  같은 이름의 함수이지만, 내부 코드는 다르게 정의해서 사용할 수 있다.

class A {
  public int test() {
    return 1;
  }
  
  public int test(int number) {
    return number;
  }
  
  public int test(int index, int number) {
    return number + index;
  }
}

  -  대신, 함수명 뿐 아니라 parameter까지 같으면 오류 발생. parameter는 달라야 한다.

 

 

이에 더해 약간 추가적인 요소로, 추상화가 있습니다.

 

 

추상화(Abstraction)

  -  공통적인 부분이나 비슷한 특성들을 묶어 이름을 붙이고 추상적인 클래스로 만드는 것

  -  추상클래스(abstract class), 인터페이스(interface)

 

 

 

 

 

 

객체 지향 프로그래밍 5대원칙(SOLID 원칙)


SRP(Single Responsibility - 단일 책임 원칙)

  -  SW의 설계 부품인 클래스와 함수는 단 하나의 책임만 가진다.

  -  즉, 설계를 잘했다는 것은 응집도는 높고, 결합도는 낮은 것이다. 이는 즉, 주어진 책임이 많아지지 않게 한다는 뜻

 

 

OCP(Open Closed - 개방 폐쇄 원칙)

  -  기존의 코드를 변경할 필요 없이(Closed) 기능을 수정하거나 추가(Open) 하는 설계를 하는 것.

  -  보통 인터페이스를 의미하기도 하는데, 인터페이스를 만들어 이를 클래스가 구현하고, 인터페이스 객체를 통해 함수를 실행한다.

 

  ex)

    Interface Card --> CheckCard class -> select()

                      -->  FamilyCard class -> select()

  가 있을 때,

 

    Card checkCard = new CheckCard();

    Card familyCard = new FamilyCard();

    checkCard.select()  -->  CheckCard의 select() 호출

    familyCard.select()  ---> FamilyCard의 select() 호출

 

 

LSP(Liskov Substitution - 리스코프 치환 원칙)

  -  MIT의 컴공 교수인 리스코프가 제안한 원칙

  -  부모 클래스와 자식 클래스 사이에는 일관성이 있어야 한다.

  -  즉, 부모 클래스 대신 자식 클래스를 사용해도 부모 클래스의 기능을 동작시키는데 문제가 없어야 한다는 것.

 

ex) (출처 - Java 객체 지향 디자인패턴 116 ~ 117p)

도형 클래스(부모) <--> 사각형 클래스(자식)

도형 클래스

  -  각이 존재한다.

  -  2차원이다.

  -  넓이가 존재한다.

 

사각형 클래스

  -  각이 존재한다.  (부모 일관성 O)

  -  2차원이다.  (부모 일관성 O)

  -  넓이가 존재한다.  (부모 일관성 O)

 

 

도형 클래스(부모) <--> 원 클래스(자식)

도형 클래스

  -  각이 존재한다.

  -  2차원이다.

  -  넓이가 존재한다.

 

원 클래스

  -  각이 존재한다.  (부모 일관성 X)    ===> 수정 필요!

  -  2차원이다.  (부모 일관성 O)

  -  넓이가 존재한다.  (부모 일관성 O)

 

 

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

  -  하나의 클래스는 자신이 사용하지 않는 인터페이스를 구현하지 않는다.

  -  즉, 기능 별로 인터페이스를 분리하는 것이 필요하다.

 

  ex)

  스마트폰이라는 클래스가 있을 때,

    문자 보낼때는 메세지 인터페이스 사용

    전화할때는 전화 인터페이스 사용

    인터넷 할 때는 인터넷 인터페이스 사용

    -> 메세지 인터페이스에 전화, 인터넷 기능이 포함되어 있지 않아야 한다. 또는 이렇게 포함된 인터페이스를 사용하지 않아도 된다.

 

 

DIP(Dependency Inversion - 의존 역전 원칙)

  -  구체화에 의존하지 않고 추상화에 의존한다.

  -  의존 시 변화하기 쉬운 것(클래스) 보다는 변화하기 어려운 것(추상 클래스, 인터페이스) 에 의존한다.

 

  ex)

  List<> list1 = new ArrayList<>();

  List<> list2 = new LinkedList<>();

 

 

 

 

 

후...

조금 이해가 되셨나요?

 

 

틀린 부분이나 잘못 적은 것이 있으면 댓글 부탁드립니다.

 

감사합니다!

 

 

 

 

 

참고

https://gbsb.tistory.com/3

https://daehwa123.com/181

https://namu.wiki/w/%EA%B0%9D%EC%B2%B4%20%EC%A7%80%ED%96%A5%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D#s-3.1

https://brownbears.tistory.com/407

Comments