이번엔 객체지향과 SOLID 원칙에 대해 알아봅시다!
프로그래밍에 조금이라도 담궈봤다! 라고 한다면 객체지향을 들어본 적이 있을텐데요..
먼저 객체지향이란 무엇인지 알아야 SOLID 원칙을 설명 할 수 있다는 것만 알아두시고.. 객체지향에 대해 알아보는 것 먼저 해보도록 합시다!
기존에 존재하던 프로그래밍 언어들은 코드들이 적혀있는 순서대로 처리가 되었는데 이런 식으로 순차적 처리가 중요하며 프로그램 전체가 유기적으로 연결되어 있도록 만드는 것이 절차지향입니다.
과거엔 컴퓨터의 처리 방식에 맞춰 순차적 처리를 기반으로 동작하도록 하는 방식이 객체지향보다 더 빠른 처리가 가능하였기에 절차지향이 더 우세했지만 최근 하드웨어의 발전 속도가 소프트웨어보다 훨씬 빨라졌기 때문에 정보를 일정하게 묶어 관리하는 객체지향이 탄생하게 되었다고 합니다.
단어 자체만 보면 조금 어려운 부분이 있기도 합니다. 하지만 객체라는 단어에 조금 더 집중해서 보면 의외로 간단하답니다!
객체의 사전적 정의는 "처리의 대상이 되는 목적물, 특징 짓고 좁히면서 실체화 시킨 것" 등이 있네요.
오.. 사전의미는 역시 어렵네요..
이걸 한가지 예를 들어 보자면
신발: 슬리퍼, 샌들, 운동화, 워커,...
상의: 셔츠, 니트, 저지,..
하의: 반바지, 긴바지, 청바지,...
의류: 상의, 하의, 신발,...
이런 식으로 어떤 물건들의 특징들을 뽑아 그 특징에 맞는 카테고리와 같은 것을 만들고 그런 카테고리들의 특징도 뽑아 하나의 큰 카테고리를 만들어 낼 수 있습니다. 이런 것이 바로 사물을 객체로써, 즉 사물의 특징들을 인식하는 과정이죠. 이렇게 보니 우리가 늘 하던 것들이죠?
이런 과정을 컴퓨터에 적용한다면 어떤 식으로 적용해야 할까? 를 고민하며 만들어 진 것이 객체지향이다~ 라고 생각한다면 간단하게 생각할 수 있습니다.
객체지향에서의 객체도 이런 객체의 의미와 비슷합니다. 우리가 인식할 수 있는,
즉 실재하는 대상들을 객체라고 하죠.
객체지향은 우리가 볼 수 있는 다양한 현상들은 이런 객체들의 상호작용으로 이뤄진다는 관점을 프로그래밍의 세계로 끌어들여 프로그래밍에 쓰이는 다양한 변수, 함수 등을 객체와 객체의 상호작용으로 표현하는 것입니다.
이때 필요한 것이 추상화 / 상속 / 다형성 / 캡슐화!!
먼저 추상화는 위의 예시에서 보이듯 의류들 중 발에 착용한다는 특징을 모아 신발 이라는 범주를 만들었는데, 이것이 바로 추상화 라고 할 수 있다. 이렇게 공통된 부분을 먼저 추려내 구현을 할 수 있다면 중복된 내용을 최소화 하면서 개발 할 수 있겠죠?
그 다음 상속은 이렇게 추상화 된 것들의 공통점들을 모아서 다시 한번 추상화 한다고 생각하면 편한데요, 이는 신발, 상의, 하의 등을 모아 의류라는 큰 범주로 만드는 과정과 같다고 할 수 있습니다. 이렇게 상위 클래스로 객체들을 모으는 것이 바로 상속!
다형성은 의류로 설명하기 어려운 부분이 있을 수도 있는데.. 후드집업을 한번 생각해봅시다. 후드집업 같은 경우엔 팔을 넣고 지퍼를 끝까지 올려 후드티 처럼, 지퍼를 열어 외투처럼, 아니면 그냥 어깨에 걸쳐 패션 아이템 처럼 입을 수도 있습니다. 이런 식으로 하나의 객체가 다양한 역할을 수행할 수 있는 것이 바로 다형성입니다.
이런 다형성에도 종류가 있는데.. 바로 오버로딩과 오버라이딩!

이런 다형성을 상속과 같이 활용한다면 여러가지의 객체를 한번에 관리 가능한 시스템도 구현 가능합니다!
패션. 이라고 한다면 옷이라던지 헤어라던지 다양한 것들이 포함될텐데 여기에 건물, 자동차 같은 것이 들어온다면 조금 모호해 지는 면이 생기겠죠? 이렇게 되면 패션이라는 것을 구성하는 것들의 조합, 상호작용 등으로 이뤄지는 것이 훼손될 수도 있습니다. 이런 것을 막기 위해 패션에는 패션과 관련된 것들만! 구성하여 묶음을 만들어 주는 것이 캡슐화 라고 할 수 있습니다.
데이터적인 관점으로 보자면 데이터를 보호하고 외부에 보여지면 안되는 정보를 은닉해 캡슐 내의 안정되거나 불안정한 부분을 구분하여 안정된 부분을 외부에 보일 수 있도록 하고 불안정한 부분은 외부로 부터 보호할 수 있도록 해 내부의 구현에 자유를 주는 한편 이렇게 캡슐화 한 것은 들어오고 나가는 정보가 같다면 같은 기능을 수행하기 때문에 다른 곳에 사용하게 만들 수 있는 중요한 부분입니다.

이 표에 잘 정리되어 있는 것 같아 가져왔다.
가장 중요한 부분은 구현 관점 / 구성 요소 / 상속 / 장단점 정도일 것 같다.
접근 방식과 관점은 순차적 구조를 가진 절차지향과 객체적 관점을 가진 객체지향의 차이에서 비롯된 것이고 구성요소와 상속 같은 것은 객체지향의 특징에서 비롯된 차이점이다.
장단점 또한 두 방식의 사용 용도를 나누는 것으로 중요하게 봐야 한다.
SOLID 원칙의 이름에서 부터 느껴지는 줄임말의 기운을 느낄 수 있네요! 한번 분석 해 봅시다.
이렇게 각각을 분리해 봤는데 각 뜻을 한번 알아봅시다.
단일 책임 원칙은 하나의 모듈은 하나의 책임을 지어야 한다.. 라는 뜻인데 이렇게 말하면 어렵죠?
위에서 말한 객체지향의 특징 4가지는 결국 객체들의 역할이 명확할 때 비로소 의미가 있어진다고 할 수 있습니다. 이런 명확한 역할들을 가지고 있기 때문에 서로의 연관성을 찾고 그것들을 서로 연결하며 공통점을 찾고 하는 것들이 가능해 지는 거죠. 만약 이런 명확한 역할이 흔들리게 된다면? 당연히 객체지향의 이점을 잃어버릴 수 밖에 없습니다. (상의를 상하의 겸용으로 만들 수는 없은 것과 같다고 해야하나..?)
이렇게 명확한 역할, 즉 책임을 가지고 있어야 해당 객체 내의 정보를 수정하거나 동작 시키는 요구를 하나의 액터로 볼 수 있습니다. 그렇지 않다면 어떤 액터가 어떤 요구를 하는지 헷갈릴 테고 이렇게 되면 원하는 동작을 제대로 시행하지 못하게 될 것입니다.
이 말의 의미 자체는 '확장에는 열려있어야 하며 수정에는 닫혀있어야한다.' 입니다.
조금 더 자세히 말하자면 기능 추가는 쉽게 할 수 있게 하되, 기존 클래스의 수정은 최소화로 하자. 라는 의미입니다. 이거.. 어디서 본 것 같죠? 바로 위에 있던 다형성!
클래스를 상속 하거나 하는 과정에서 오버라이딩과 오버로딩을 사용한다고 했는데 이것이 바로 확장에 열려있는, 즉 기능추가를 손쉽게 할 수 있도록 하는 것입니다. 만약 기능이 추가될 때 마다 객체를 수정해야 한다면 수정된 객체는 기존의 객체와 다르기 때문에 우리가 원하는 동작을 그대로 할 수 있을 지 매번 체크를 해야 합니다. 하지만 이와 같이 확장에 열려있고 수정에 닫혀있는 상태라면 추가되는 기능은 하위 클래스 등을 이용해 기능이 추가 될 것이기 때문에 기존의 객체는 기존 동작을 원활하게 수행 가능할 것입니다.
이 또한 결국 객체지향의 특징을 살리기 위한 원칙이라고 할 수 있겠네요!
우선 의미를 본다면 하위 타입은 상위 타입을 대체할 수 있어야 한다는 뜻인데요, 대체가 가능하다 라는 의미를 다르게 본다면 밖에서 볼 땐 차이 없이 사용할 수 있어야 한다 라는 뜻으로도 볼 수 있습니다. 이는 즉 일반화 관계가 성립 되어야 한다는 뜻인데.. 사실 이 의미는 개방-폐쇄 원칙과 유사하게 느껴지기도 합니다. 특히 기능 확장시 유의해야 하는 원칙으로 다가오는 느낌이 강한데요, 기능을 확장할 때 해당 기능을 연관성이 없는 객체에 하위로 추가하게 된다면 이는 하위 객체가 상위 객체를 대체할 수 없게 되겠죠? 따라서 객체를 상속관계로 엮거나 이를 이용해 기능을 추가 할 때 알맞은 위치에 알맞은 관계로 정의하고 정리해라~ 라는 말로 생각할 수 있겠습니다.
아.. 이 부분을 보니 인터페이스에 대해 먼저 정리해 뒀어야 하는데.. 라는 후회가 몰려오네요 ㅋㅋㅋㅋ 인터페이스는 자바를 만져보신 분들은 아실텐데요. 객체의 메서드들을 상속 받아 여러개의 객체에 같은 이름의 함수들을 지정할 수 있게 해 비슷한 동작을 하는 메서드들을 모아두는 객체 라고 할 수 있습니다.
이런 인터페이스를 분리하라는 말은 각 역할에 맞게 인터페이스 상속을 해야 한다는 의미로, 다른 종류의 목적과 용도를 가지고 있다면 서로 분리하여 구분할 수 있게 해야 한다는 것입니다.
음.. 뭔가 단일 책임 원리와 비슷하지 않나요? 역할을 명확히 해라! 라는 점에서 말이죠~
인터페이스를 사용하는 객체들의 기준에 맞게 분리하여 구현해야 한다 라는 점은 하나의 인터페이스가 하나의 책임을 지어야 한다고 생각 해도 되겠네요!
의존 역전 원칙은 어떤 객체를 직접 참조하는 것이 아니라 그 객체의 상위 요소(추상 클래스, 인터페이스 등)로 참조 하라는 원칙 입니다. 즉 변화가 많이 일어나는 곳이 아니라 변화가 적게 혹은 거의 일어나지 않는 곳을 참조해야 한다는 말입니다. 변화가 자주 일어날 수 있는 객체를 참조한다면 변화가 일어날 때 마다 참조되는 부분도 변화를 줘야 한다는 문제점이 생기고 이는 다형성을 통해 만들어진 객체를 무용지물로 만드는 행위가 됩니다. 이 또한 객체지향의 방향성에 위배된다고 할 수 있겠네요! 만약 이 원칙이 지켜지지 않는다면 변경에도 기존 동작을 원활하게 수행할 수 있다는 개방 폐쇄 원칙도 위배가 될 것입니다. 변경사항에도 동일한 참조를 이용해 동작할 수 있도록 의존 역전 원칙을 따라야 다른 원칙에도 위배되지 않고 잘 동작 할 수 있을 것입니다!
객체지향 프로그래밍은 개발해야 하는 대상을 객체로 보며 해당 객체들의 관계를 중점적으로 프로그램을 구현하는 방식이다. 특징으론 추상화, 캡슐화, 상속, 다형성이 있다.
SOLID 원칙은 객체지향의 추상화와 다형성을 활용하기 위한 방법들 이라고 할 수 있으며 절차지향 프로그래밍과 객체지향 프로그래밍의 차이에서 비롯된 것들이라고 할 수도 있다.