프로그램을, 객체들의 모임으로 파악하고자 하는것. 각각의 객체는 메시지를 주고받고 데이터를 처리하는것.(협력) 유연하고 변경이 용이하기 때문에 대규모개발에서 많이사용
유연하다?
레고블럭 조립하듯이
컴포넌트를 쉽고 유연하게 변경하면서 개발할 수 있는 방법이라는 뜻
이를 다형성이라고 부름(Polymorphism)
다형성
역할과 구현으로 세상을 구분하는식으로 비유해보자
예시1) 운전자-자동차
운전자라는 역할, 자동차라는 역할이 있음
자동차 구현으로 k3, 아반테, 테슬라모델3를 제작
자동차 역할을 3개의 다른자동차들로 구현을 함
k3를 운전자가 타다가 아반떼로 차를 바꾼다하더라도 운전을 할 수 있음. 어차피 자동차로서의 역할은 똑같이 가졌기때문에 운전자에게 어떠한 영향도 미치지 않음
왜 이게 가능하냐면, 자동차 역할 interface에 따라서 자동차를 만들었음. 운전자는 자동차 interface에만 의존해있기때문에 상관없음.
왜 이렇게 개발했냐면, 운전자를 위해서임. 운전자가 각기 다른 자동차에 대해 알필요없도록 하기 위해서임. 자동차 역할만 지키도록한다면 어떤차가 나와도 운전자는 계속 운전할 수 있기때문에, 자동차 시장은 무한히 확장할 수 있음. 대상을 바꾸지 않고 자동차를 출시할 수 있음
클라이언트에게 영향을 주지않고 새로운 기능을 제공할 수 있음.
역할과 구현으로 세상을 구분했기때문에 가능한것.
클라이언트는 새로운걸 배울 필요가 업슴
예시2) 공연무대
로미오 역할과 줄리엣 역할이 있음
배우는 누구든지 상관없음. 만약 주배우들이 다 몸이 아프다? 무명배우로라도 대체가 가능한것임
어떻게는 공연은 굴러갈 수 있음. 이게 바로 유연성, 대체가능성임
역할과 구현으로 구분하면 세상이 단순, 유연해지고, 변경도 편리
클라이언트는 인터페이스만 알면됨. 내부구조를 몰라도됨. 내부구조가 바뀌어도 영향을 받지 않는다. 구현 대상 자체를 변경해도 영향을 받지 않음.
자바언어의 다형성을 스프링은 활용함.
역할 = 인터페이스
구현 = 인터페이스를 구현한 클래스, 구현객체
객체 설계시 인터페이스를 먼저 부여하고, 그 역할 수행하는 구현 객체 만들기
(상속으로도 가능하긴한데 단일상속만 가능하고 별로니까 인터페이스가 좋음)
객체의 협력이라는 관계를 생각해야함
혼자있는 객체는 없음
클라 - 요청, 서버-응답
수많은 객체 클라와 객체서버는 협력 관계를 가짐
크게 보면 서버와 시스템끼리로도 생각가능
자바 언어의 다형성
오버라이딩 - 기능을 넘어서 타버린다.(재정의)
오버로딩 - 여러개 많이 초과해서 로딩했다.(메소드 여러개)
오버라이딩된 메서드가 실행됨
다형성의 본질
인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경 가능
클라를 변경하지않고, 서버 구현기능을 유연하게 변경
정리 클라를 변경하지 않고 서버 구현기능을 변경하면서 유연하게 대처가 가능하므로, interface를 잘짜는게 중요
한계
역할 자체가 변하면 클라 서버 모두에게 큰 변경 발생
인터페이스를 안정적으로 잘 설계하는게 진짜진짜 중요
스프링과 객체 지향
객체 지향의 꽃은 다형성
다형성이 진짜 중요
스프링은 다형성을 극대화해서 이용할수있게 해줌
ioc, di는 다형성을 활용해서 역할 구현을 편리하게 다룰 수 있도록 지원
근데 제대로 이해하려면 다형성말고, SOLID도 잘 알아야함. 중요중요!!! (이거 면접에 많이 나온대)
SOLID 원칙이란?
SRP 단일 책임 원칙
Single Responsibility Principle
한 클래스는 하나의 책임만
모호하긴 한데, 변경이 있을때 파급효과가 적으면 단일 책임 원칙을 잘 따른것.
OCP 개방-폐쇄 원칙
OpenClosed Principle
소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀있다
다형성을 생각하면서 이해하면됨.
전에 예시로 얘기했던 Memory하고 Jdbc MemberRepository 그거 보면 클라이언트쪽에서 코드를 변경함. 그러므로 걔는 다형성을 사용했지만 OCP원칙을 지킬 수 없다. 이걸 해결하려면 객체를 생성하고, 연관관계 맺어주는 별도의 조립/설정자가 필요(나중에 배울거임 Di로)
LSP 리스코프 치환 원칙
Liskov substitution principle
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서, 하위 타입의 인스턴스로 바꿀 수 있어야한다. (정확성이라는게 그냥 컴파일이 되는것을 얘기하지 않음.)
다형성에서 하위클래스는 인터페이스 규약을 다 지켜야한다는것
예시) 자동차 인터페이스의 엑셀은 앞으로 가라는 기능임. 만약 이걸 뒤로 가게 구현한다면 LSP를 위반하는것
ISP 인터페이스 분리 원칙
Interface Segregation Principle
특정 클라이언트를 위한 인터페이스 여러개 > 범용 인터페이스 하나
(전에 클린코드에서 얘기한거같은 느낌)
적당한 크기로 인터페이스를 쪼개는게 좋다는것.
명확해지고, 대체 가능성이 높아짐(고치는게 편해지니까)
DIP 의존관계 역전 원칙
추상화에 의존해야지, 구체화에 의존하면 안됨.
클라이언트 코드가 실제 구현 클래스말고 인터페이스를 바라봐야한다는 말임.(전에 다형성, 역할기능분리랑 같은 얘기임)
아까 얘기했던 memberRepository가 DIP도 위배함. memberRepository에 클라가 잘 의존중인데, memberRepository에 MemoryMemberRepository를 선언함. 그러니까 결국 클라코드는 구현체도 알고있게되는거임. 즉, 의존중인거