웹에서 2D 물리엔진 사용하기 #1 Matter.js 시작하기
TypeScript로 알아보는 객체 지향 프로그래밍(OOP) #1 OOP
2020-03-28
Explanation
한달에 적어도 두개의 포스팅 쓰자는 마음에, 조금은 밀린 방학숙제를 하는 느낌이 없지 않아 있지만..
오늘은 객체 지향 프로그래밍(OOP)에 대해서 포스팅을 해보려 합니다. 만약 이 주제로 포스팅을 계속 이어간다면, 다음은 SOLID 그리고 디자인 패턴으로 이어서 포스팅을 하려 합니다. (만 쭈욱 잘 이어갈 수 있을지 모르겠네요..)
생각해보면 그동안 “OOP”라는 이야기를 꾸준히, 정말 오랜 시간 들어왔던 거 같아요. 그만큼 중요하다는 것이고, 아직도 어렵게 느껴지는 걸 보니.. 설명하기도 어렵고 이해하기도 참 어려운 거 같아요..
나무위키를 참고해보면 “프로그램을 설계하는 방법론이자 개념의 일종”이라고 적혀있어요.
https://namu.wiki/w/객체%20지향%20프로그래밍
위 나무위키에서처럼 객체 지향 프로그래밍을 아주 간단하게 정의한다면, “객체를 중심으로 한, 더 나은 프로그래밍을 위한 하나의 방법론” 이 아닐까 생각이 들어요. 그리고 조금 더 자세히 정의한다면 “SC Jeong”님의 “소프트웨어 디자인” 블로그에서 이야기 한,
“객체 지향 프로그래밍 이란 캡슐화, 다형성, 상속 을 이용하여 코드 재사용을 증가시키고, 유지보수를 감소시키는 장점을 얻기 위해서 객체들을 연결 시켜 프로그래밍 하는 것”
저는 굉장히 얕은 지식으로 키워드 중심으로 포스팅을 하게 될 것 같아서, 조금 더 깊이 있는 이해를 위해서는 위에 이야기한 “SC Jeong”님의 “소프트웨어 디자인” 블로그 글을 보시면 더 좋을 것 같습니다.
https://vandbt.tistory.com/10
흔히 OOP가 무엇인가에 대해 이야기할때 “캡슐화”, “상속”, “다향성”에 대해서만 많이 이야기 되는 것 같아요. 물론 캡슐화도 상속도 다향성도 중요하지만 자칫 그런 이해가 OOP를 너무 좁은 의미에서 이해하게 하진 않을까 생각이 들어요. 위에 참고한 “소프트웨어 디자인” 블로그에 글의 내용처럼 “캡슐화”, “상속”, “다향성”은 OOP를 구성하는 특징이고 요소들이긴 하지만 그게 OOP의 전부이거나 OOP와 non-OOP를 나누는 기준은 아니니까요.
방법론, 인식론, 유물론, 관념론… 뭔가 저 ‘론’으로 끝나는 말은 뭔가 알 거 같으면서도 막상 이야기하려면 굉장히 어려운 어려운 말인거 같아요.
우선 가장 쉬운 방법은 철학사전을 참고해보면,
1. 과학에서 검토를 행할 때 여러 가지 방법을 총괄하여 방법론이라고 한다.
2. 과학적 인식을 얻기 위한, 또 세계를 변혁하기 위한 방법을 고찰하는 것을 방법론이라고 한다.
여기에서 말하는 방법론은 2번에 가까울 거 같아요.
프로그래밍의 역사를 생각해보면 짧다고 하면 짧을 수도 있지만, 시간 대비 변화의 폭은 굉장히 컸던거 같아요. 개인적으로, 지금과 같은 컴퓨터 같은 컴퓨터가 보급되었던 걸 생각하면 586 컴퓨터(팬티엄)가 우리집엔 95년도 쯤 들어온 거 같아요. 여하튼 30~40년 동안…
(다시 생각해보니 40년은 짧은 시간이 아니네요. (팩맨이 80년에 나왔으니까…))
40년이 넘는 오랜 시간동안 무수히 많은 프로그래머들이 새로운 프로그램을 개발하는 그리고 유지 보수하는 그 과정 속에서 더 나은 프로그래밍 방법에 대해 고민하고, 또 고민하던 노하우들 중 하나가 OOP 인 것이지요.
이런 예가 맞는지 모르겠는데, 옛날부터 피타고라스 같은 사람들이 모여서 수학 문제 고민하다가 지금 우리가 “수학의 정석” 보면서 공부하는 거랑 비슷하지 않을까요?
조금 다른 점은 수학의 정석은 이과 갬성이고 OOP는 문과 갬성으로, 수학은 비교적 문제에 대한 해답이 명확한 방면, 프로그래밍은 명확한 정답보다는 주어진 상황에 따른, 더 좋은 선택을 하기 위한 방법을 말하는 거죠.
여기까지 읽으며, 너무 간단한 이야기를 왜 이렇게 주렁주렁 적어논거지? 라는 생각이 들 수 도 있는데,
방금 저도 그런 생각이 들었습니다…
캡슐화란 데이터와 로직의 결합을 이야기하는데요. 잘못됬다고 말하려는건 아니지만, 일반적으로 캡슐화를 은닉화에 중점을 두고 이야기하거나 혹은 둘은 같게 이야기하는 경우가 있는거 같아요.
하지만 캡슐화에 핵심은 데이터와 로직의 응집성이랍니다.
정리가 잘 되지 않지만.. 의식의 흐름대로 적어보자면,
캡슐화란 데이터와 로직의 결합을 이야기하고. OOP에서의 좋은 캡슐화를 위하여.
1. 마틴 아저씨의 SOLID의 S(단일 책임 원칙)에 따라 클래스는 하나의 책임을 갖고 모든 기능은 해당 클래스의 책임과 부합화도록 캡슐화 해야한다.
2. 클래스는 인터페이스와 구현으로 나누어 설계하고 구현은 외부와 노출을 최소화 하여 모듈간의 결합도를 떨어뜨려 유지보수성을 높인다.
그러니까, 여기서 2번에 따라, 은닉화는 캡슐화의 파생된 보조 개념이니까, 캡슐화와 은닉화를 너무 하나로 생각하지 않는게 좋을 거 같아요.
그리고 캡슐화에 대하여 “도리안”님의 블로그에서 이해하기 좋은 예시가 있어서 함께 추가하면,
“사전적인 의미로서 캡슐화는 무엇인가를 캡슐에 넣음을 의미합니다. 우리가 일상생활에서 가장 많이 접하는 캡슐이 바로 알약이지요. 캡슐에 약을 넣고 그것을 닫지요. 이것이 캡슐화의 한 예입니다. 알약은 캡슐과 약(가루 또는 알갱이)로 구성됩니다. 그렇다면 약국에서 캡슐이 왜 사용될까요? 가장 큰 이유는 먹기 편하기 때문이죠. 또 다른 이유는 캡슐의 크기가 정해져 있기 때문에 약의 섭취량을 조절하기가 쉽습니다. 캡슐 없이 약을 먹는 것이 불가능하지는 않습니다. 하지만 담을 수 있는 양이 각기 다른 숟가락 등으로 약을 먹는 것은 권장량보다 더 많은 약을 먹을 가능성이 있습니다. 즉, 약이 남용될 수가 있는 거죠. 이런 저런 이유로 캡슐에 담은 약은 우리에게 유용합니다.”
http://blog.naver.com/PostView.nhn?blogId=netrance&logNo=110096417364
한번 더 엮어서 이야기하자면, 앞서 이야기한 1번. 단일 책임 원칙에 따라 위와 같은 알약을 캡슐화 하는 클래스에 이스트소프트의 알약의 관련한 데이터가 있으면 안되겠죠…
그리고 2번에 따라 얄약을 얻을 수 있는 인터페이스만 외부에서 알 수 있을 뿐, 알약의 만드는 방법에 대해서는 외부에서 알 수 없어야 하겠죠??
상속은 어떤 클래스를 상위 클래스로하여 하위 클래스에서 상위 클래스의 데이터나 함수를 사용할 수 있도록 하는 것을 말하죠..?
조금 더 정확하게 이야기하면, 클래스를 추상화하는 구조라고 해야 할까요??
그러니까…
아메리카노 클래스와 라떼라는 클래스가 있다고 하면 둘 다 동일하게 에스프레소 샷이 들어가죠? 그래서 커피라는 상위 클레스를 두고 상위 클레스에 에스프레소 샷추가 라는 함수를 추가하면, 함수의 재사용성이 증가한다는 것과 또 아메리카노와 라떼를 커피로 한 단계 더 추상화 한것이라고 할 수 있답니다.
상속 자체는 대부분 익숙한, 단순한 개념이지 않나 생각이 들어요. 상속 자체는 단순한데, 어떻게 사용하느냐가 OOP에서는 중요하고, 또 굉장히 어려운 부분인거 같아요. 이 부분은 추후에 SOLID나 디자인패턴을 이야기할때 자주 생각하게 되지 않을까 싶습니다.
간단하게 하나만 되짚고 지나가자면, 접근 제한자 정도??
언어마다 조금씩 차이는 있겠지만, 일반적으로??
public : 자신과 상속된 하위 클래스에서도, 외부 에서도 접근이 가능.
protected : 자신과 하위 클래스에서만 접근이 가능하나 외부에서 접근 불가능
private : 자기 내부에서만 사용이 가능.
다향성은 하나의 변수나 메서드가 상황에 따라 다르게 해석되는 것을 이야기하는데요.
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.3p
크게 오버라이딩과 오버로딩을 많이 이야기하는데요.
A라는 상위 클래스에 test라는 메서드가 있고 B라는 하위 클래스에 동일하게 test라는 메서드가 있을때, 하위 클래스로 만들어진 인스턴스에 test 메서드를 호출하면 하위 클래스에 정의된 test 메서드가 실행되는데 이게 오버라이딩.
오버로딩은 동일한 메서드가 매개변수에 따라 여러게 정의되고 호출할 때의 매개변수에 따라 다르게 동장하도록 할 수 있는 것인데요.
이 부분은 자바스크립트에서는 지원하지 않아요.
하지만 간단하게 예를 들어보면 아래와 같은거에요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Example { test(p1: string) { return 'string'; } test(p1: number) { return 'number'; } test(p1: string, p2: number) { return 'multi parameters'; } } const example = new Example(); example.test('abc'); // 'string' example.test(1); // 'number' example.test('abc', 1); // 'multi parameters' |
부족하거나 잘못된 내용이 많이 있을 수 있습니다…
댓글로 알려주시면 감사할 것 같아요 :)
OOP에 대해 이야기할 때 “캡슐화”, “상속”, “다향성”에 대해서만 많이 이야기되는 것 같다고 시작해 놓고 “캡슐화”, “상속”, “다향성”만 이야기한 건 함정…