1. 객체 지향 프로그래밍이란
프로그램은 행사나 연주회 등에서 "XXX 프로그램" 이라고 말하는 것처럼, 작성해놓은 코드가 한 줄씩 차례대로 실행되는 순차적인(절차적인) 방식으로 동작한다. 절차지향 프로그래밍이란, 이런 프로그램의 기본적인 특성에 맞춰서 하나의 파일을 순차적으로 실행되도록 구성하는 것을 말한다.
그러나 객체 지향 프로그래밍은 단순히 한개의 파일에서 순서대로 작성해놓은 코드가 실행되도록 하는 것이 아니라, 여러 개의 독립된 단위, 즉 "객체" 들의 모임으로 프로그램을 바라보는 시각을 말한다. 자바에서는 클래스나 인터페이스 파일들이 객체라고 할 수 있겠다.
이렇게 생성된 객체들은 서로 데이터를 주고받으며 동작한다. 객체들끼리 데이터를 주고 받으며 작동하는 프로그램을 만드는 이유는, 프로그램을 수정하거나 개선하기 용이하기 때문이다.
보통 비유를 통해 많이 설명하는데, 이전 글에서 이미 공부한 바가 있다.
https://whitepro.tistory.com/16
대표적인 예로 자동차가 정말 많이 등장하는데, '자동차 역할' 이라는 인터페이스가 있으면 운전자는 '자동차 역할'에만 의존하면 된다. 다시 말해서 운전자는 자동차를 운전하는 방법만 알고 있으면 된다. 이렇게 되면 차종이 세단이든, SUV든, 스포츠카든 상관없이 운전을 할 수 있게된다.
김영한님의 강의에서는 연극을 예시로 든다. "로미오와 줄리엣"을 연기하는데, 로미오인 남 주인공이 특정 여자 배우와만 연기할 수 있다면, 여자 배우에게 무슨 일이 생겨서 다른 배우로 바뀌는 경우에는 문제가 발생할 것이다. 로미오는 줄리엣이라는 "역할"에 맞춰서 연기를 해야, 줄리엣 역할을 하는 배우가 누가 됐든 연극을 이어나갈 수 있을 것이다.
자바는 이러한 다형성에 기반한 언어다. 객체를 설계할 때 역할과 구현을 명확히 분리하여 객체지향에 의한 장점을 최대한으로 살려낼 수 있다. 다만, 역할인 인터페이스가 변경되면 프로그램을 다시 설계해야하므로, 인터페이스를 안정적으로 잘 구현하는 것이 매우 중요하다.
2. 좋은 객체 지향 설계의 5가지 원칙(SOLID)
실무를 하다보면 5가지 중에 몇 가지는 조금이나마 와닿는 것 같다. 아마 정말 경험이 많은 개발자가 많은 시행착오를 통해 정리한 원칙이지 않을까 싶다.
딱 5가지인게 조금 의심스럽긴 하지만.. 외우기 좋게 SOLID로 표현한 건 마음에 든다. 뭔가 튼튼하게 코딩하라는 말인가 ㅎㅎ
이후 글에서 직접 코딩을 하면서 이 5가지 원칙에 대해 자연스럽게 배울 것이다. 강의 내용을 글로 정리하면서 이 개념이 무뎌질 수 있겠지만, 계속해서 가장 중요한 이 원칙과 객체 지향의 원리에 대해 상기하면서 코딩을 해야 실무에서도 도움이 될 수 있을 것 같다.
1. SRP(Single Responsibility Principle), 단일 책임 원칙
하나의 객체는 하나의 책임만 가져야 한다는 원칙이다. 그런데 책임이라는 기준이 모호하다. 그래서 다르게 표현하자면, 객체의 변경이 있을 때 파급효과가 적도록 설계하는 것을 의미한다고 생각하면 된다.
2. OCP(Open/Closed Principle), 개방-폐쇄 원칙
객체는 확장에는 열려있으나 변경에는 닫혀있어야 한다. 즉 인터페이스를 통해 여러 구현체들을 만들면서 어떤 구현체를 쓸지는 변경해도 되지만, 인터페이스나 구현체의 코드를 바꾸는 방식으로 프로그래밍하는 것은 좋지 않다는 뜻이다.
기본적으로 인터페이스에 연결된 구현체 코드를 변경하려면 결국 코드를 변경해야한다.
ex) AnimalRepository repository = new PandaRepository(); 에서 repository를 LionRepository로 바꾸고 싶다면, AnimalRepository repository = new LionRepository(); 로 코드를 직접 수정해야한다.
이 문제를, 스프링에서는 설정자를 만들어줌으로써 해결한다. 스프링의 핵심 개념인 DI(Dependency Injection)을 통해 해결한다. 뒤에서 자세히 다룬다.
3. LSP(Liskov Substitution Principle), 리스코프 치환 원칙
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 된다는 내용이다. 한 번 정한 규칙을 다른 규칙으로 치환하면 안된다고 이해하면 된다. 예를 들면 자동차 인터페이스의 엑셀은 앞으로 가라는 기능인데, 엑셀을 밟으면 뒤로가게 만든다면 LSP 위반이다. 아마도 기존에 기획하고 설계한대로 인터페이스를 만들고, 이를 상속받는 구현체들도 원래 의도대로 기능이 동작되도록 해야함을 의미하는 것 같다.
4. ISP(Interface Segregation Principle), 인터페이스 분리 원칙
인터페이스를 잘게 분리하라는 말이다. 마치 SRP 처럼, 하나의 큰 인터페이스는 책임이 명확하지 않고 변경에 유연하지 못할 수 있으므로 최대한 분리하여 명확성과 대체 가능성을 높이는 것이 유리하다는 내용이다. 예를 들어 자동차 사용자에 대한 큰 인터페이스가 있다면 사용자를 운전자, 조수 등으로 분리하여 표현하는 것이 좋다.
5. DIP(Dependency Inversion Principle), 의존관계 역전 원칙
실무하면서 가장 처음 배우는 내용인 것 같다. 추상화에 의존해야지, 구체화에 의존하면 안된다는 원칙이다. 만약에 아래와 같은 구조라면,
보통 편하게 프로그래밍 하기에는 Impl1이나 Impl2와 같은 구현체를 다른 객체에서 끌어와서 사용하는 것이 좋다. 구현체에 메소드들이나 변수들이 직접 표현되어 있기 때문인데, 이렇게 사용하면 나중에 변경이 힘들어진다. 즉 Impl1을 불러와서 Impl1 내부의 어떤 메소드를 사용하고 있었는데, Impl2로 바꿔야되는 상황이오면 코드를 통째로 다 바꿔야하는 상황이 올 수 있다.
어쨌든 DIP를 지키기 위해서는 itemService = new itemServiceImpl1(); 이라고 되있던걸 itemService = new itemServiceImpl2(); 라고 코드를 바꿔줘야 하므로 OCP를 지킬 수 없게 된다. 그래서 나중에 배우겠지만, DIP도 OCP와 마찬가지로 스프링에서의 설정자 기능을 이용해서 이를 지키게 된다.
다음 글부터는 실제로 프로젝트를 생성해본다!
참조
1. 인프런_스프링 핵심 원리 기본편_김영한 님 강의
www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard
'Programming-[Backend] > Spring' 카테고리의 다른 글
[스프링 기초] 3. 프로젝트의 구조 및 생성 (0) | 2021.05.25 |
---|---|
[TIL] BeanUtils.copyProperties, 엔티티 객체 복사하기 (0) | 2021.05.25 |
[스프링 기초] 1. 스프링의 탄생, 기본 개념 (0) | 2021.05.06 |
[TIL] PO(Parameter ObjecT)와 DTO(Data Transfer Object)는 구분해서 쓰자 (0) | 2021.05.06 |
[에러] Cannot deserialize instance of, Leading zeroes not allowed, Swagger 스웨거 날짜, 리스트 입력 (0) | 2021.05.05 |