객체 지향 프로그래밍
객체지향 프로그래밍이란 무엇인가?
객체 지향 프로그래밍은 어렵다.
클래스를 만들고 상속하여 추상성과 다형성을 높이고 어쩌구 저쩌구…
단순히 클래스를 만들고 객체를 만들면 객체지향인가?
적어도 과거의 나는 그렇게 생각했던 것 같다.
만약 누군가 직접 저 질문을 물어봤다면 아니라고 대답했겠지만,
내 코드는 단순히 클래스랑 객체를 만들고 객체지향이라 우기고 있었다.
https://velog.io/@eddy_song/alan-kay-OOP
창시자 앨런 케이가 말하는, 객체 지향 프로그래밍의 본질
앨런 케이는 '객체 지향 프로그래밍'이라는 네이밍을 잘못 지었다고 인정했다.
velog.io
최근 한 글을 보며 객체지향이란 뭘까 조금 영감을 얻었다.
객체지향의 최고 장점은 확장성이다
내가 생각하기에 객체 지향의 최고 장점이자 존재 이유는 “확장성”이다.
누군가에겐 틀린 말일 수 도 있겠지만, 적어도 나에겐 아니다.
객체지향이란 “무엇”인가가 아닌, 객체지향을 “왜” 써야하는가에 초점을 맞추고
객체 지향에 대한 글들을 다시 읽어보니,
객체지향이란 무엇인지 조금은 이해하게 된 것 같다.
print(a){
if(a==int) printf("%d", a);
if(a==char) printf("%c", a);
if(a==str) printf("%s", a);
}
만약 a란 값을 출력하는 함수가 있다 치자,
C언어로 이를 작성한다면 a의 type에 따라 형식지정자를 일일히 지정해줘야 할것이다.
만약 a에 새로운 타입이 들어온다면? a의 값이 null이 될 수 있다면? 머리가 아파진다
a.print();
b.print();
c.print();
a = {data = 1, print() = printf("%d", a)]
b = {data = 'b', print() = printf("%c", b)]
c = {data = "cc", print() = printf("%s", c)]
이를 객체 지향적으로 바꿔보자.
만약 a,b,c라는 객체가 각각 print 함수를 갖고있고,
메인 함수에선 그저 메서드를 호출해주기만 한다면?
d = {data = 1.2, print() = printf("%f", d);
e = {data = null, print() = printf("null");
새로운 타입을 출력해야한다면, 또는 null을 체크해야 한다면
그저 해당 객체에 새로운 print() 함수를 추가해주면 된다.
메인 함수에선 어차피 print()를 사용하라는 메시지를 보내고있을 뿐,
print() 함수의 내용은 알수도 없고 관심도 없다. 그렇다. 이게 객체지향이다!
메시지, 캡슐화, 동적 바인딩
객체지향의 창시자, 앨런 케이가 말하길
OOP의 본질은 메시지, 캡슐화, 동적 바인딩 이 3가지라고 한다.
- 관련있는 데이터와 프로시져를 찾아서 묶고 다른 객체가 내부를 건드리지 못하게 한다. (캡슐화)
- 다른 객체의 데이터나 프로시져가 필요할 때는 메시지 요청한다. 메시지를 받는 객체는 스스로 처리 방법을 선택한다. (메시징)
- 메시지를 받는 객체는 그때 그때 달라질 수 있다. (동적 바인딩)
위 예제에서, 메인함수는 메서드를 호출하기만 했다.
메인 함수는 메서드의 내용이 뭔지 알수도 없고 알아서도 안된다. 이것이 캡슐화.
메인함수는 print() 메서드를 호출하기만 했고,
print() 함수의 내용은 객체에 따라 달라진다. 이것이 메시징
새로운 자료형과 null에 대해 새로운 print()메서드를 작성했다. 이것이 동적바인딩이다
객체 지향은 객체가 중점이 아니고, 절차 지향은 절차가 중점이 아니다.
'객체 지향'이라는 말을 쓰다보니, 너무 객체나 클래스에 초점이 가게 된다.
OOP의 본질을 흐리는 것 같다. 진짜 핵심은 '메시징'이다.
클래스를 만들고 개체를 상속하는 것은 객체지향을 가장 효과적으로 사용하는 방법이지만,
클래스를 사용한다는 것이 객체 지향적이란 것은 아니다.
클래스와 객체를 그저 하나의 자료구조로 사용한다면, 그것은 절차 지향과 다를바가 없다.
내 코드가 그렇더라 (눈물) ;ㅅ;
절차 지향 방식은 "데이터"를 중심으로 "함수"를 구현한다.
위 print(a) 함수는 a라는 데이터의 값(자료형)에 따라 적절한 output을 제공해야한다.
반면 객체 지향 방식은 "기능"을 중심으로 "메서드"를 구현한다.
a의 값은 중요하지 않다. 모든 객체들은 자신의 값에 알맞은 메서드를 지니고있다.
순서에 맞게 메서드를 호출하기만 하면 된다.
객체 지향 방식은 비절차적이지 않다.
사실 생각해보면 당연한 이야기이다.
프로그램이라면 “실행” 될것이고 실행엔 “순서”라는게 있을 수 밖에 없는데,
하필 이름이 “절차” 지향이고 “객체” 지향이라,
마치 객체 지향은 절차가 없단 것 처럼 느껴진다.
https://m.blog.naver.com/atalanta16/220249264429
객체지향 vs 절차지향??
객체지향 프로그래밍을 소개하는 많은 강의 및 입문서에서는 보통 절차지향 프로그래밍 기...
blog.naver.com
“절차” 지향 방식은 실행 절차를 세우고 → 이에 맞춰 자료구조와 함수를 설계한다.
반대로 “객체” 지향 방식은, 자료구조와 함수를 묶어 객체로 만들고 → 이들의 실행 순서를 작성한다.
절차 방식에선 절차를 구현하는 것이 알파이자 오메가이지만,
OOP에선 각 메서드들을 구현하고, 이를 올바른 순서대로 호출하기만 하면 된다.
즉 절차의 중요성이 상대적으로 떨어질 뿐, 객체 지향에도 절차는 중요한 개념이다.
정리
절차 지향 방식에서, 모든 input은 a()라는 함수를 거친다.
이를 반대로 말하면 a()란 함수는 모든 input에 대해 올바른 ouput을 제공해야한다.
즉 새로운 값을 추가하면 a()를 이에 맞춰 수정해야하고,
그러면 a()와 연관된 모든 함수에 문제가 없는지 확인해야한다.
객체지향 방식에서, 모든 객체는 자신만의 a() 메서드를 지닌다.
즉 새로운 값을 추가하면, 해당 객체에 새로운 a()를 넣으면 된다.
이 새로운 a()는 기존의 a()와 완전히 분리되어 있으므로,
해당 a()를 추가했을때의 여파가 적다.
또한 절차지향에선 a()를 수정하면 a()를 호출한 모든 부분을 살펴야한다.
반면 객체지향에선 a()를 수정할때 무조건 객체만 살피면 된다.
a()란 메서드도, a()에 인자로 들어갈 값도 전부 한 객체에 존재하기 때문이다.