목차
클린코드 2장부터 전반적으로 객체지향의 설계 원칙인 SOLID 에 대한 내용이 언급됩니다.
객체지향이 무엇이고 어떻게 탄생하게 되었는지 간단하게 알아보고
객체지향의 원칙인 SOLID 원칙에 대해 알아봅니다.
객체지향이란?
프로그래밍 방법론 중 하나이다.
프로그램을 제작하는데에서 필요한 언어들의 특성 중 하나다.
탄생배경
객체지향은 서양 철학과 연관있다.
int a;
정수 / a
C++
복사
int 는 정수라는 개념이다.
a 는 정수에 해당되는 실체이다.
플라톤은 이데아(이상)라는 개념적인 것에 대해 중요하게 생각했고, 아리스토텔레스는 개념이라는 것 보다는 구현을 더 중요시 했다. ⇒ 이러한 개념과 구현의 분리는 객체지향의 큰 특징 중 하나이며, 서양철학이 객체지향의 철학이 기초가 되었다고 볼 수 있다.
객체지향 프로그램은 어떤 대상에 대해 추상적인 개념을 설계하고 실체로 구현하게 된다.
여기서 추상&개념 = abstract class 가 되고, 실체는 구현체(Implmentation)가 된다.
객체지향의 예시
규모가 작은 동네 치킨집 (자영업자)을 떠올려보자
사장님이 하는일은 다음과 같다.
1.
치킨튀기기
2.
카운터보기
3.
홀 서빙
이 모든 일을 규모가 작기 때문에 사장님이 다 커버 할 수 있다.
하지만 치킨집이 번영해서 프렌차이즈가 되었다면?
매장의 규모도 커지고, 방문하는 손님의 규모도 커짐에 따라서,
사장님 혼자 모든일을 다 할 수 없게 된다.
⇒프로그램의 규모가 성장하게되면, 기능적 요소들을 분리해서 나눌 필요가 있다.
규모가 커지면서 기업화 되었다 기업화 된다. 이것은 곧 팀 혹은 부서가 나뉘게 된다는 얘기이다.
절차지향 언어는 한 사람이 뛰어나게 잘하는게 중요했지만, 규모가 커지면서 여러사람이 일하는것이 효율이 좋아지므로 여러사람이 일하는 환경이 될 수 밖에 없다.
여러 사람이 되면 관계가 생긴다. 여러 사람들은 각자 상호작용을 하면서 관계가 생긴다.
여기서 “각자” 에 해당되는 것들이 객체가 되고, 이 객체(각자)들의 관계를 구현하고 연결해서 하나의 프로램을 이루게 된다.
이런 관계를 정의하고 개념과 구현을 나누는 것이 객체지향이다.
객체지향에 대해 알아보았으니, 이제 객체지향적인 프로그래밍을 하기 위한 원칙을 알아보자.
위의 내용들은 다음 영상을 정리한 것이므로 자세히 알아보고 싶다면 참고해주세요
영상
객체지향의 5원칙 (SOLID 원칙)
Single Responsibility Principle 단일 책임 원칙
사진과 같이 로봇이라는 클래스가 있다고 가정해보자.
왼쪽은 한 로봇이 [ 셰프, 정원사, 그림그리기, 운전사 ] 의 역할을 모두 한다 .
하나의 클래스에서 이렇게 많은 일을 하게되면 이 클래스의 정체성이 무엇인지?
무엇을 하는 클래스인지 쉽게 알아보기 어렵다.
어떤 기능이 있는지 확인하는데에 시간이 걸린다.
⇒따라서 오른쪽 그림과 같이 각각 하나의 역할을 뚜렷하게 하는게 좋다
역할마다 분리된 로봇(클래스) 여러개가 존재하는게 좋다.
•
한 클래스는 하나의 책임만 가져야한다.
•
클래스는 하나의 기능만 가지며, 어떤 변화에 의해 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다.
•
가독성 향상과 유지보수가 용이해진다.
•
SRP 책임이 분명해지므로 변경에 의한 연쇄작용으로부터 자유롭다
Open-Close-Prinsiple 개방-폐쇄 원칙
자르는 기능을 하는 로봇이 → 펌웨어 업데이트를 한 후 → 칠만 가능한 로봇이 되었다
자르는 기능을 하는 로봇이 → 펌웨어 업데이트를 한 후 → 자르기 + 칠 이 가능한 로봇이되었다 (확장)
⇒기존의 기능을 유지하면서, 새로운 기능을 추가할 수 있어야 한다.
•
소프트웨어 요소는 확장에는 열려있으나, 변경에는 닫혀있어야 한다.
•
변경을 위한 비용은 줄이고, 확장을 위한 비용은 극대화한다
•
요구사항의 변경이나 추가사항이 발생해도,
기존 구성요소에는 수정이 일어나지않고,
기존 구성 요소를 쉽게 확장해서 재사용한다.
•
객체지향의 추상화와 다형성을 활용한다.
Liskov Substitution Principle 리스코프 치환 원칙
자식클래스 (Edan) 커피를 만드는 부모(sam) 를 상속받았지만 부모의 기능인 커피만들기 기능을 못한다.
부모클래스의 기능을 수행할 수 있으며 이를 바탕으로 더 확장된 기능들을 제공한다
⇒자식클래스가 부모클래스를 상속받은 상태로, 부모클래스의 역할을 할 수 있어야한다.
•
(자식)서브 타입은 언제나 (부모)기반 타입으로 교체할 수 있어야 한다.
•
서브 타입은 기반 타입이 약속한 규약을 지켜야한다(접근제한자, 예외 포함)
•
클래스 상속(expend), 인터페이스 상속(implement)을 이용해 확장성을 획득한다.
•
다형성과 확장성을 극대화하기 위해 인터페이스를 사용하는 것이 더 좋다.
•
합성(composition)을 이용할 수도 있다.
Interface Segregation Principle 인터페이스 분리 원칙
모든 로봇에 대해 일괄적인 설계도 작성 → 안테나가 없는 로봇에게 안테나 관련 기능이 필요한가?
역할을 분리하여 설계도 작성 → 필요한 기능만 갖춘 로봇 펌웨어
•
자신이 사용하지 않는 인터페이스는 구현하지 말아야한다.
•
최소한의 인터페이스만 구현한다
•
클래스를 이용하는 클라이언트가 여러개이고,
클라이언트가 클래스의 특정 부분만 이용한다면,
여러 인터페이스로 분류하여 클라이언트가 필요한 기능만 전달해야 한다
•
SRP가 클래스의 단일 책임 / ISP는 인터페이스의 단일책임
Dependency Inversion Principle 의존성 역전 원칙
로봇과 일체형 피자커터 팔을 통해 피자를 자를 수 있다 → 피자-로봇 연결이 되어있다(의존)
팔이랑 로봇이랑 분리가 가능하다 → 갈아 끼울 수 있다.
•
상위 모델은 하위모델에 의존하면 안된다.
둘 다 추상화에 의존해야 한다.
추상화는 세부 사항에 의존해서 안된다. 세부사항은 추상화에 따라 달라진다
•
하위 모델의 변경이 상위 모듈의 변경을 요구하는 위계관계를 끊는다.
•
실제 사용관계는 그대로지만 추상화를 매개로 메세지를 주고받으면서 관계를 느슨하게 만든다.