반응형

1. 객체지향의 특징 4가지
추상화 : 객체들의 공통적인 특징(기능, 속성)을 도출하는것
캡슐화 : 실제 구현되는 부분을 외부에 드러나지않도록 은닉
상속성 : 하나의 클래스가 가진 특징(함수,데이터)을 다른 클래스가 그대로 물려받는것
다형성 : 다른 방법으로 동작하는 함수를 같은 이름으로 호출하는것, 객체지향의 꽃, 오버로딩 / 오버라이딩

- 다형성
역할(인터페이스)과 구현(인터페이스를 구현한 객체)으로 세상을 구분

예시1)
자동차 역할을 K3, 아반떼, 테슬라로 구현하더라도 운전자는 운전자 역할이 가능하다.
운전자를 클라이언트라고 했을 때, 자동차 역할을 그대로 사용할 수 있다.
자동차의 역할과 구현을 구분한 이유는 운전자(클라이언트)에 영향을 주지 않고 새로운 자동차를 무한히 출시 할 수 있음.


예시2)
로미오 역할을 구현한 장동건, 원빈 / 줄리엣 역할을 구현한 김태희, 송혜교 
배역만 만들어두고, 배우는 언제든지 유연하게 변경할 수 있다.
로미오 역할, 줄리엣 역할을 누가 하든 서로에게 영향을 끼치지 않음.

※ 역할과 구현을 구분하면 세상이 단순해지고, 유연해지며 변경도 편리해짐.
: 클라이언트는 대상의 역할(인터페이스)만 알면됨.
: 클라이언트는 구현 대상의 내부구조를 몰라도됨.
: 클라이언트는 구현 대상의 내부구조가 변경되어도 영향을 받지 않음.
: 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않음.


2. Java의 다형성
역할 = 인터페이스, 구현 = 인터페이스를 구현한 클래스, 구현 객체
객체를 설계 할 때 역할과 구현을 명확히 분리
객체 설계시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체 만들기
(상속도 다형성이 가능하지만 인터페이스로 만드는것이 나음)

 

예시)
다형성으로 인터페이스를 구현한 객체를 실행 시점에서 유연하게 변경이 가능하다.

public class MemberService{
	// 인터페이스를 참조 변수로 선언
	// 인터페이스를 오버라딩하여 구현한 구현 객체 중 원하는 구현 객체로 생성자 함수를 클라이언트가 호출
	private MemberRepository memberRepository = new MemoryMemberRepository(); // 기존 코드
	private MemberRepository memberRepository = new JdbcMemberRepository(); // 변경 코드
}

 

※ 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있음.

 

- 다형성의 본질을 이해하려면 ?

객체는 객체끼리 협력 관계이다.
클라이언트 : 요청, 서버 : 응답
혼자있는 객체는 없음. 수 많은 객체 클라이언트와 객체 서버는 서로 협력관계를 가짐
클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경 할 수 있다.



3. 좋은 객체 지향 설계의 5가지 원칙(SOLID)
- SRP 단일 책임 원칙 : 한 클래스는 하나의 책임만 가져야한다.
변경이 있을때 파급효과가 적으면 단일 책임 원칙을 잘 따른것 (객체의 생성과 사용을 분리)
※ 책임의 범위를 잘 조절해야함


- OCP 개방 폐쇄 원칙 : 소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀있어야한다. (다형성)
역할과 구현을 분리, 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현하는것.

※ 생각해보기

public class MemberService{
	private MemberRepository memberRepository = new MemoryMemberRepository(); // 기존 코드
	private MemberRepository memberRepository = new JdbcMemberRepository(); // 변경 코드
}

클라이언트가 구현 클래스를 직접 선택하고있으니 OCP를 지키지 못함.
구현 객체를 변경하려면 클라이언트 코드를 변경해야함.
다형성으로 서비스를 구현했지만 OCP를 지킬 수 없음.
※ 해결방법 : 객체를 생성하고 연관관계를 맺어주는 별도의 조립, 설정자가 필요함(스프링 컨테이너가 해줌 DI, IoC 컨테이너)


- LSP 리스코프 치환 원칙 : 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야한다.
다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 함. 컴파일은 잘 되더라도 규약을 위배하면 LSP 위반.
자동차 인터페이스의 엑셀은 앞으로가라는 기능, 뒤로가게 구현하게되면 LSP 위반, 느리더라도 앞으로가야함.


- ISP 인터페이스 분리 원칙 : 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다.
자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스로 분리
사용자 클라이언트 -> 운전자 클라이언트, 정비사 클라이언트로 분리
정비 인터페이스 자체가 변해도 운전자 클라이언트에 영향을 주지 않음
인터페이스가 명확해지고, 대체 가능성이 높아짐


- DIP 의존 관계 역전 원칙 : 프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다.
스프링의 의존성 주입은 이 원칙을 따르는 방법중에 하나.
클라이언트 코드가 구현 클래스를 바라보지 말고 인터페이스를 바라보라는 뜻.
역할에 의존해야지 구현에 의존하지 말라는것.
의존 = 내가 그 코드를 안다.

MemberService 클라이언트는 구현 객체를 알고있음(MemoryMemberRepository)

public class MemberService{
	private MemberRepository memberRepository = new MemoryMemberRepository();
}


클라이언트가 구현객체를 알고있는 것도 DIP 위반



4. 스프링과 객체 지향
스프링은 다형성을 극대화하여 이용할 수 있게 도와줌.
IoC, DI는 다형성을 활용해서 역할과 구현을 편리하게 다룰수 있도록 지원.
스프링을 사용하면 레고 블럭을 조립하듯, 공연무대의 배우를 선택하듯 구현을 편리하게 변경 할 수 있음.

 

- 스프링은 다음 기술로 다형성 + OCP, DIP를 가능하게 지원
DI(Dependency Injection) : 의존관계, 의존성 주입
DI 컨테이너 제공 : 자바 객체들을 컨테이너 안에 넣어두고 의존관계를 서로 연결해주고 주입해주는 기능을 제공
-> 클라이언트 코드의 변경없이 기능 확장 
-> 쉽게 부품 교체 하듯 개발 가능

※ 공연을 설계하듯이 배역만 만들어두고, 배우는 언제든지 유연하게 변경할 수 있도록 만드는것이 좋은 객체 지향 설계이다.

반응형

+ Recent posts