📖책의 내용을 요약하니 자세한 부가설명이 궁금하시면 보시는걸 추천드립니다. 📖
1. 절차지향과 객체지향
1.1 절차지향
데이터를 조작하는 코드를 별도로 분리해서 함수와 프로시저로 만들고, 데이터를 조작하는 방식으로 프로그램을 작성.
최초에 절차지향 방식 구현은 쉽다. 하지만 규모가 커질 수록 다음 같은 문제들이 발생
- 데이터 타입이나 의미를 변경할 때, 함께 수정해야할 관련 프로시저가 증가
- 하나의 데이터를 다른 의미로 사용하는 경우가 발생
1.2 객체지향
객체지향은 데이터 및 데이터와 관련된 프로시저를 객체(object)라고 불리는 단위로 묶는다
객체지향 기법으로 작성된 프로그램은 객체들로 구성이 된다.
객체는 다른 객체에 기능을 제공하기 위해 프로시저를 이용하며, 프로시저는 해당 객체의 데이터만 접근이 되고 외부 객체의 데이터는 접근할 수 없다.
2. 객체
2.1 객체의 핵심은 기능을 제공하는 것
위에서 언급한 데이터 및 데이터와 관련된 프로시저는 물리적인 특성.
객체를 정의할 때 객체가 제공해야할 기능이 핵심이고, 내부에 저장될 데이터로는 객체가 정의되지 않는다.
2.2 인터페이스와 클래스
객체가 제공하는 기능을 오퍼레이션(Operation)이라 부름
오퍼레이션 사용법은 3개이며, 3개를 합쳐 시그니처라 함.
- 기능 식별 이름
- 파라미터 및 파라미터 타입
- 기능 실행 결과 값
객체가 제공하는 오퍼레이션 집합을 객체의 '인터페이스(interface)'라고 부르며 일종의 명세서나 규칙이라 생각하면 된다. 자바 같이 특정 언어의 interface는 아니다.
인터페이스는 실제 객체의 기능 구현에 대한 내용이 없다. 구현을 정의하는 것을 클래스(class)라 부른다.
* 객체간의 인터페이스를 맞춘다는 것은 개념적인 의미이지 언어에서 제공하는 인터페이스가 아니다.
2.3 메시지
오퍼레이션의 실행을 요청(request)하는 것을 '메시지(message)'를 보낸다고 한다.
특정 언어에서 메서드를 호출하는 과정이 메시지를 보내는 과정에 해당된다.
3. 객체의 책임과 크기
객체는 객체가 제공하는 기능으로 정의를 다시 말하면 객체마다 자신만의 책임(responsibility)이 있다는 의미.
객체가 갖는 책임을 정의하는 것을 인터페이스라 생각하면 된다. 이 책임을 결정하는 것이 객체 지향 설계의 출발점
객체의 책임이 커질수록 절차지향적으로 구조가 변질되니 책임은 작을 수록 유연함을 갖는다.
* 객체의 크기와 관련된 원칙으로 단일 책임 원칙(Single responsibility principle)이 있다.
4. 의존
구현하다보면, 다른 객체의 기능을 이용해서 자신의 기능을 완성하는 객체가 나타난다.
어떤 객체가 다른 객체를 생성하거나 다른 객체의 메서드를 호출할 때, 그 객체에 의존(dependency)한다고 표현한다.
의존하는 것은 의존하는 객체에 변경이 일어나면 나도 함께 변경될 가능성이 높다는 것을 뜻한다.
* 의존의 영향은 전파되는 특징이 있고, 다시 나에게 되돌아온다는 의미로 순환의존이라 부른다. 관련된 원칙으로 의존 역전 원칙(Dependency inversion principle)이 있다.
5. 캡슐화
캡슐화(encapsulation)는 객체의 내부를 감추는 것으로 캡슐화를 통해 변화가 다른 곳에 미치는 영향을 최소화한다.
5.1 절차지향 방식코드
class Member {
private String name;
private String grade;
private String address;
public Member(String name, String grade, String address) {
this.name = name;
this.grade = grade;
this.address = address;
}
...
}
// 데이터를 가져와 사용
class Order {
public void xxOrder(Member member) {
if ("VIP".equals(member.getGrade())) {
System.out.println("배송무료");
} else {
System.out.println("배송비 3000원");
}
}
}
class Event {
public void xxEvent(Member member) {
if ("VIP".equals(member.getGrade())) {
System.out.println("이벤트 대상");
} else {
System.out.println("X");
}
}
}
class Coupon {
public void xxCoupon(Member member) {
if ("VIP".equals(member.getGrade())) {
System.out.println("쿠폰 2배 발급");
} else {
System.out.println("쿠폰 발급");
}
}
}
...
데이터를 여기저기 사용하는 절차지향 방식이다.
여기서 주소가 서울이면 VIP와 똑같이 혜택받을 수 있게 정책이 변경된다고 생각해보자.
if ("VIP".equals(member.getGrade())
|| "서울".equals(member.getAddress())) {
...
}
Order,Coupon,Event 모두 위와 같이 변경해야한다.
시간이 지나고 규모가 커질수록 문제는 점점 많이 생기는 절차지향 방식이다.
5.2 캡슐화 된 기능 구현
객체지향 방식으로 재구성해보자. 캡슐화는 기능이 내부적으로 숨기는 것이라 했다.
// 객체지향 방식
class Member {
...
public boolean isVip() {
return "VIP".equals(benefit);
}
}
class Order {
public void order(Member member) {
if (member.isVip()) {
System.out.println("배송비 3000원");
} else {
System.out.println("배송무료");
}
}
}
class Coupon {
public void xxCoupon(Member member) {
if (member.isVip()) {
System.out.println("쿠폰 2배 발급");
} else {
System.out.println("쿠폰 발급");
}
}
}
class Event {
...
}
Member 내부에 isVip로 VIP 인지 확인하는 메서드를 추가했다.
이전과 다르게 Order, Coupon, Event는 Member에게 VIP 확인요청만 하게된다.
똑같이 서울 지역도 VIP 혜택을 준다고 해보자.
// 객체지향 방식
class Member {
...
public boolean isVip() {
return "VIP".equals(benefit)
|| "서울".equals(address);
}
}
class Order {
public void order(Member member) {
if (member.isVip()) {
System.out.println("배송비 3000원");
} else {
System.out.println("배송무료");
}
}
}
class Coupon {
public void xxCoupon(Member member) {
if (member.isVip()) {
System.out.println("쿠폰 2배 발급");
} else {
System.out.println("쿠폰 발급");
}
}
}
class Event {
...
}
Member의 isVip()만 변경되고 이를 가져다 사용하는 곳은 수정할 필요가 없다.
5.3 캡슐화의 결과는 내부 구현 변경의 유연성 획득
캡슐화를 잘 할수록 보다 쉽게 구현 변경 가능.
5.4 캡슐화를 위한 두 개의 규칙
1) Tell, Don't Ask
- 데이터를 물어보지 않고(가져오지 말라), 기능을 실행해 달라 말하기
2) 데미테르의 법칙(Law of Demeter)
- 메서드에서 생성한 객체의 메서드만 호출
- 파라미터로 받은 객체의 메서드만 호출
- 필드로 참조하는 객체의 메서드만 호출
6. 객체 지향 설계 과정
객체지향 설계란 다음 같은 반복 과정
1. 제공할 기능을 찾아 세분화하고 기능을 알맞는 객체에 할당
- 기능에 필요한 데이터를 객체에 추가한다. 반대로 데이터를 추가하고 기능을 넣는다
- 기능은 최대한 캡슐화
2. 객체 간에 어떻게 메시지를 주고받을 지 결정한다
3. 위의 과정을 지속적으로 반복
* 구현 과정에서 한 클래스에 여러 책임이 있다면 새로운 객체로 책임을 분리하면 된다.
'서적 > 객체지향과 디자인패턴' 카테고리의 다른 글
챕터6, DI(Dependency Injection)와 서비스 로케이터 (0) | 2021.06.04 |
---|---|
챕터5, 설계 원칙 : SOLID (0) | 2021.06.03 |
챕터4, 재사용 : 상속보단 조립 (0) | 2021.06.03 |
챕터3, 다형성과 추상 타입 (0) | 2021.06.03 |
객체지향과 디자인패턴을 시작하며 (0) | 2021.06.02 |