새롭게 맞이한 2023년, 다들 어떤 마음가짐으로 올해를 시작하고 계신가요?
예년과 달리 벌써 공채를 시작한 대기업들이 있어 자기소개서랑 면접 준비로 바쁜 하루를 보내고 계실 것 같아요.
그래서 이번달 토픽으로 기술 면접 심화 질문 파헤치기를 준비해 보았습니다.
보통 Java 기술면접의 단골질문은
- 객체지향이 무엇인가요?
- OOP의 4가지 특징이 무엇인가요?
두 가지입니다. 하지만 일부 회사에서는 조금 특별한 질문을 던지기도 하는데요, 바로 "객체지향 설계 원칙이 무엇인가요?" 혹은 "객체 지향 개발 5대 원리를 말해보세요" 라는 질문입니다.
객체 지향 특징 네 가지(다형성, 추상화, 캡슐화, 상속)은 아는데... 5대 원칙은 뭐지? 싶은 분들이 계실 겁니다. 오늘 준비한 주제는 바로, 이 질문에 대한 답!
객체 지향 설계 5원칙 SOLID 입니다.
객체지향 설계 5대 원칙이 필요한 이유는 우리의 일상생활만 살펴보아도 알 수 있습니다. 예를 들어, 우리가 취업할 수 있는 회사가 두 개 있다고 가정해봅시다. 한 회사는 해당 회사 CEO의 혁신 원칙대로 운영되는 회사입니다. 다른 회사는 원칙 없이 운영되는 회사고요. 개인 취향 차이는 있겠습니다만, 보편적으로 원칙이 있는 회사가 없는 회사보다 신입의 적응력, 회사 운영, 성장 측면에서 상승 곡선을 그리게 됩니다. 이처럼 일상생활에서 원칙은 개인과 단체의 삶을 윤택하게 만들어줍니다.
그리고 이게 바로 객체지향 설계 5대 원칙이 필요한 이유입니다. 객체지향 설계 원칙을 따르면 좀 더 유지보수, 확장이 쉬워지고 유연해집니다. 디자인 패턴에 비해 볼륨이 작아 간과될 수 있는 원칙이지만, SOLID에 대해 잘 알고 있다면 보다 소프트 웨어 프로그래밍의 탄탄한 기반이 될 것입니다.
단일 책임의 원칙(SRP : Single Responsibility Principle)
단일 책임의 원칙은 작성된 클래스는 하나의 기능만 가지며 클래스가 제공하는 모든 서비스는 그 하나의 책임을 수행하는 데 집중 되어있어야 한다는 원칙입니다. (여기서 책임은 기능이라고 생각하시면 이해가 쉽습니다)
예를 들면, 자동차의 모든 기능을 'Car'라는 클래스에 작성하면 하나의 클래스가 굉장히 무거워지게 됩니다. 이 문제를 해결하기 위해 'seat', 'heater' 등 기능으로 클래스를 쪼개면 각 클래스가 하나의 책임을 가지게 되는 것입니다.
SRP 원리를 적용하면 책임 영역이 확실해진다는 장점이 있습니다. 또 책임을 적절하게 분배함으로써 코드의 가독성이 향상되고, 유지보수가 용이해집니다. 이 원리는 OCP(개방 폐쇄 원칙, Open Closed Principle)원리 뿐 아니라 다른 원리들을 적용하는 기초가 됩니다.
이 원리는 다른 원리에 비해 비교적 단순한 개념을 가지지만, 실무의 프로세스는 매우 복잡하고 변경이 빈번하기에 이를 적용해서 직접 클래스를 설계하긴 쉽지 않습니다. 따라서 평소에 많은 연습이 필요합니다.
개방폐쇄의 원칙(OCP : Open Close Principle)
개방폐쇄의 원칙이란 소프트웨어 구성요소(컴포넌트, 클래스, 모듈, 함수)는 확장에 열려있고, 변경에는 닫혀 있어야 한다는 원리입니다. 변경을 위한 비용은 가능한 줄이고 확장을 위한 비용은 가능한 극대화 해야한다는 것으로, 요구사항의 변경이 발생하더라도 기존 구성요소는 수정이 일어나지 말아야 하며, 기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 한다는 의미입니다.
예를 들어, 'Animal'이라는 객체에 '울기()'라는 메서드가 있을 때, 'Animal("강아지")', 'Animal("고양이")'로 사용을 하면 기존 'Animal' 객체를 계속 수정해야 합니다. 하지만 'Animal'을 상속받는 방식으로 변경하면 기존 코드의 수정 없이 확장이 가능합니다.
OCP를 가능하게 하는 중요 매커니즘은 추상화와 다형성입니다. 이는 객체 지향의 장점을 극대화 하는 아주 중요한 원리라 할 수 있습니다.
리스코프 치환의 원칙(LSP : The Liskov Substitution Principle)
리스코프 치환의 원칙은 서브타입은 언제나 기반 타입으로 교체할 수 있어야 한다는 원칙입니다. 즉, 서브 타입은 언제나 기반타입과 호환될 수 있어야 한다는 뜻입니다. 따라서 서브타입은 기반타입이 약속한 규약(public interface, 메소드가 던지는 exception 포함)을 지켜야 합니다.
예를 들어, size가 10이라는 특징이 있는 '로보트'를 상속받는 'AI 로보트' 클래스가 있을 때, 'AI 로보트'에서 사이즈 수정이 일어나면 안된다는 것입니다. 상속을 할 때는 부모 것을 대신해 사용해도 정상작동 하게끔 상속을 받아야 합니다. 만약 그게 안된다면 상속을 받으면 안된다는 게 리스코프 치환의 원칙입니다. 정리하면, 상위타입의 객체를 하위타입의 객체로 치환해도 정상작동 해야한다는 것입니다.
[적용 방법]
1. 만약 두 개체가 똑같은 일을 한다면 둘을 하나의 클래스로 표현하고 이들을 구분할 수 있는 필드를 둡니다
2. 똑같은 연산을 제공하지만, 이들을 약간씩 다르게 한다면 공통의 인터페이스를 만들고 이를 구현합니다 (인터페이스 상속)
3. 공통된 연산이 없다면 완전 별개인 2개의 클래스를 만듭니다
4. 만약 두 개체가 하는 일에 추가적으로 무언가를 더 한다면 구현 상속을 합니다
인터페이스 분리의 원칙(ISP : Interface Segregation Principle)
ISP 원리는 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다는 원칙입니다. 즉 어떤 클래스가 다른 클래스에 종속될 때 가능한 최소한의 인터페이스만을 사용해야 한다는 것입니다. (또는 '하나의 일반적인 인터페이스보다는 여러개의 구체적인 인터페이스가 낫다'고 정의할 수도 있습니다.) SRP가 클래스의 단일 책임을 강조한다면 ISP는 인터페이스의 단일 책임을 강조합니다. 다만 ISP는 어떤 클래스나 인터페이스가 여러 책임/역할을 갖는 것을 인정합니다. ISP는 인터페이스 분리를 통해 변화의 적응성을 획득하게 됩니다.
예를 들면, '이동수단'이라는 클래스를 '자전거' 클래스가 상속받는다면, '이동수단'에 있는 '시동걸기', '기름넣기' 등의 사용하지 않는 것들도 상속받게 됩니다. 이는 인터페이스 분리의 법칙을 위반한 것입니다. ISP 원칙을 지키기 위해서는 '시동걸기', '기름넣기' 등 구체적인 인터페이스를 만들어 '자전거' 클래스가 상속받게 해야 합니다.
의존성 역전의 원칙(DIP : Dependency Inversion Principle)
의존 관계 역전(Dependency Inversion)이란 구조적 디자인에서 발생하던 하위 레벨 모듈의 변경이 상위 레벨 모듈의 변경을 요구하는 위계관계를 끊는 의미의 역전입니다. 실제 자용 관계는 바뀌지 않으며, 추상을 매개로 메세지를 주고 받음으로써 관계를 최대한 느슨하게 만드는 원칙입니다.
예를 들어, '고양이'라는 클래스 안에는 '먹이'라는 내부 필드가 있다고 가정해봅시다. 그런데 이 내부필드는 '참치'라는 데이터 타입을 받게 됩니다. 그런데 이 '고양이'가 '먹이'를 '연어'로 바꾸려고 합니다. 이때, 기존 데이터 타입이 '참치'로 되어있기 때문에 코드를 수정하려면 굉장히 번거로워집니다. 이런 경우, '참치'와 '연어'가 '피쉬'라는 상위클래스를 상속받고 있다면, '참치'나 '연어'같은 하위 개념을 사용하지 말고 상위 개념인 '피쉬'를 사용하라는 것이 의존 역전의 원칙입니다.
이상으로 객체지향 설계 5가지 원리를 알아보았습니다.
2023년 모두 원하는 기업, 원하는 직무에 꼭 합격하기를 바라면서 마무리하겠습니다.
감사합니다.
참고자료
[2월] 배포 Tip 방출 : AWS 2차 비밀번호 설정하기 (0) | 2023.02.19 |
---|---|
[1월] :: 백엔드 탐구생활 :: RESTful API의 모든 것 (0) | 2023.01.30 |
[12월] 비전공자의 넓고 얕은 SSAFY이야기 String ver4 = "수학" (0) | 2022.12.31 |
[12월] 초보 개발자 레벨업 :: 그래서 "도커"가 뭔데? (0) | 2022.12.15 |
[11월] 싸피 비전공자 합격 팁 한 번에 보기! "8기 합격자가 말해주는 꿀팁모음.zip" (0) | 2022.11.30 |