객체지향의 사실과 오해

NNIIE·2023년 5월 21일
0

review

목록 보기
1/2
post-thumbnail

1장. 협력하는 객체들의 공동체

정리

출근길에 카페에 들러 커피를 주문하는 과정을 객체지향 패러다임웹 어플리케이션에 빗대어 설명하고 있다.

  1. 손님은 출근길에 카페에 들러 캐시어에게 커피를 주문한다.
  2. 캐시어는 손님에게 커피를 주문받고 해당 커피의 제조를 바리스타에게 요청한다.
  3. 바리스타는 캐시어에게 요청받은 커피를 제조해 전달한다.
  4. 캐시어는 전달받은 커피를 손님에게 전달한다.
  5. 손님은 커피를 받고 맛있게 먹는다.

이로써 카페라는 웹 어플리케이션은 하나의 Request - Response 사이클을 처리했다.

생각

카페라는 어플리케이션은 손님, 캐시어, 바리스타 객체들이 자신들의 명확한 역할을 가지고 서로 상호작용하는 객체지향적인 어플리케이션으로 설계되었고 객체들은 인터페이스를 통해 서로 요청을 주고 받으며 자신들이 맡은 책임을 다한다.

객체들은 서로 열어둔 인터페이스를 통해 요청만 주고 받을 뿐 다른 객체들이 요청을 어떻게 처리하는지에 대해선 알 수 없다.

이것은 핵심적인 로직의 처리를 외부에 알리지 않는 캡슐화 의 원칙을 잘 지키고 있는데
만약 캐시어 객체가 바리스타 객체가 제조하는 아메리카노 제조법을 알고있어서 즉, 바리스타가 아메리카노 제조법을 외부에 공개해 버려서 캐시어가 그 제조법에 의존하게 되버리면 해당제조법으로 아메리카노를 요청할 수 있다.

이 경우 아메리카노 제조법이 바뀔 시 변경되어야 할 부분은 바리스타 객체의 아메리카노 제조법과 더불어 캐시어 객체의 변경되기전 아메리카노 제조법을 바탕으로 한 커피제조 요청 까지 변경되어야 하는 유지보수에 좋지 못한 어플리케이션이 되버린다.

1장에선 객체지향에 대해 가볍게 설명하고 있는데 그중에서도 SRP(단일책임원칙)캡슐화에 중점을 두고 설명하는거 같다.

2장. 이상한 나라의 객체

정리

1장에서 설명한 자율적인 객체에 대해 조금더 깊게 설명하고 있다.

  1. 객체의 상태를 조회할 수 없다는 접근제어자의 개념에 대해 설명하고있다.
  2. 동일성 / 동등성 에 대해 설명한다.
  3. 객체가 적절한 책임을 가지는것 부터 시작하는 책임주도설계 에 대해 간단히 설명한다.

생각

@Getter
@EqualsAndHashCode(of = {"식별자로_사용될_필드들"})
public class 앨리스 {

    private static final int 문을_통과할수_있는_키 = 40;
    private static final int 음료를_마실때_줄어드는_키 = 10;

    private int;
    private String 위치;
    private 음료 음료;

    public void 문을통과한다() {
        while (> 문을_통과할수_있는_키) {
            음료를_마신다();
        }
        위치 = "정원";
    }

    private void 음료를_마신다() {
        음료.마셔진다();
        키를_줄인다();
    }

    private void 키를_줄인다() {
        if (< 음료를_마실때_줄어드는_키) {
            throw new RuntimeException("줄어들 키가 없습니다.");
        }=- 음료를_마실때_줄어드는_키;
    }

}

@Getter
@EqualsAndHashCode(of = {"식별자로_사용될_필드들"})
public class 음료 {

    private static final int 요청시_줄어드는_물의_양 = 1;

    private int 음료의양;

    public void 마셔진다() {
        if (!음료가있는지()) {
            throw new RuntimeException("줄어들 음료가 없습니다.");
        }
        음료의양 = 음료의양 - 요청시_줄어드는_물의_양;
    }

    private boolean 음료가있는지() {
        return 음료의양 >= 요청시_줄어드는_물의_양;
    }

}

3장. 타입과 추상화

정리

지하철 노선도와 트럼프를 통해 추상화와 LSP 에 대해 설명하고 있다.

생각

/* 
해당 Collection 에서 2보다 큰 원소만을 포함한 Collection을 반환 받고싶을 뿐이다.
실제로 stream 내부에서 동작하는 각 Collection 에 최적화된 알고리즘을 알아야 할 필요가 없다.
*/
Set<Integer> set = Set.of(1, 2, 3, 4, 5);
List<Integer> list = List.of(1, 2, 3, 4, 5);

Set<Integer> setResult = set.stream()
		.filter(element -> element > 2)
		.collect(Collectors.toSet());

List<Integer> listResult = list.stream()
		.filter(element -> element > 2)
		.collect(Collectors.toList());
// LSP
public interface Action {
	void attack();
}

public class Warrior implements Action {
	@Override
	public void attack() {
		System.out.println("칼로 공격한다.");
	}
}

public class Wizard implements Action {
	@Override
	public void attack() {
		System.out.println("마법공격을 한다.");
	}
}

public void attack(Action action) {
	action.attack();
}

Action warrior = new Warrior();
Action wizard = new Wizard();
attack(warrior);
attack(wizard);

4장. 역할, 책임, 협력

정리

앨리스가 본 재판을 통해 각 객체들이 서로 메시지를 주고받고 스스로의 책임을 다하는 과정을 보여주고 있다.

  • 판사와 증인의 역할과 책임을 이해하고 수행할 수 있는 객체가 있으면 판사와 증인이 다른 객체로 바뀌어도 재판 어플리케이션은 무리없이 돌아가는 상황을 말하며 대체가능성과 추상화에 대해 설명한다.
  • 객체지향 설계는 데이터가 아닌 객체들의 책임부터 시작한다.

생각

다양한 요구사항에 맞춰 최대한 객체지향적이고 효율적인 설계를 하려고 많은 노력을 하고있지만 항상 성에 차지 않는데 책에서 말한 바퀴를 반복적으로 발명할 필요가 없다는 말이 와닿는다.
이미 검증된 다양한 디자인 패턴들을 깊게 공부해야 할 때가 아닌가 싶다.

시간이 흐르면서 어플리케이션은 복잡해지고 방대해졌다.
다뤄야 하는 데이터는 커졌고 하드웨어가 좋아져도 병렬처리는 필수적이다.
현재 자바가 함수형 프로그래밍을 도입한 이유도 상태를 가지지 않는, input - output 이 확실한 함수형 프로그래밍으로 병렬처리를 효과적으로 지원하기 위해서라고 생각한다.
우리는 객체지향이 주는 여러 장점을 포기할 수 없다.
그래서 자바진영은 객체지향 설계에 핵심로직은 함수형 프로그래밍으로 처리하는건 아닐까?
그렇다면 시간이 지나서 나올 새로운 패러다임은 어떤 형태가 될까?

5장. 책임과 메시지

정리

  • 다형성 을 사용하면 송신자가 수신자의 종류를 몰라도 된다.
    • 왕에게 영향을 주지 않고 메시지를 수신할 객체의 타입을 자유롭게 추가할 수 있다.
  • 객체지향 설계는 메시지를 바탕으로 한 객체들의 협력관계를 구성하는 것
  • 메시지가 협력에 필요한 객체를 발견하게 해야 한다.
  • ISP
  • 캡슐화

생각

// 다형성
public interface Testimony {
	void testify();
}

public class Alice implements Testimony {
	@Override
	public void testify() {
		System.out.println("앨리스는 증언한다.");
	}
}

public class Hatter implements Testimony {
	@Override
	public void testify() {
		System.out.println("모자장수는 증언한다.");
	}
}

public class King {
	public void orderToTestify(Testimony testimony) {
		testimony.testify();
	}
}

King king = new King();
Alice alice = new Alice();
Hatter hatter = new Hatter();

king.orderToTestify(alice);
king.orderToTestify(hatter);
/*
Utility Class 는 어떤 관점으로 봐야하는가?
아래 Utility Class는 인스턴스화가 막혀 있으니 시작부터 객체지향에 정면으로 위배된다.
trade-off 는 접근성, 간결함, 인스턴스비용 vs 객체지향
상황에 따라 적절히 사용하고 있지만 나는 아직 그 적절한에 대한 명확한 답은 모호하다.
*/
@UtilityClass
public class JsonHandler {

	private static final Gson gson = new Gson();

	public static <T> T convertJsonObject(final String jsonString,
										  final Class<T> type) {
		return gson.fromJson(jsonString, type);
	}

	public static <T> String convertListJson(final List<T> elements) {
		return gson.toJson(elements);
	}

	public static <T> JsonArray convertJsonArray(final List<T> elements) {
		return gson.toJsonTree(elements, new TypeToken<List<T>>(){}.getType()).getAsJsonArray();
	}

	public static <K, V> String convertMapJson(final Map<K, V> elements) {
		return gson.toJson(elements);
	}

}

6장. 객체 지도

정리

  • 지도를 통해 객체지향 설계에 대해 설명하고 있다.
    • 자주 변경되는 기능이 아닌 안정적인 구조를 따라 객체를 구성해라
  • 도메인 모델을 중심으로 하는 설계를 설명하고 있다.
  • 유스케이스

생각

이번장의 핵심은 OCP 와 도메인 모델인거 같다.
OCP - 확장에는 열려있어야 하지만, 변경에는 닫혀 있어야 한다.

이 책은 끊임없는 반복을 통해 객체지향의 몇가지 성질에 대해 서술하고 있다.
지금까지 SOLID의 모든 원칙이 나왔는데 객체지향과 SOLID 원칙에 대해 기초적인 감을 잡기에는 적절해 보이지만 다음 스텝을 밟기엔 무리가 있다.

또한 계속되는 반복과 개인적인 생각으론 쓸데없지만 마치 외워야만 할것같은 어떤것에 대한 정의들이
책을 점점 더 읽기 힘들게 만드는거 같다.

7장. 함께 모으기

정리

커피전문점에 대한 도메인을 지금까지의 내용을 바탕으로 설계하고 구현하고 있다.

  • 훌륭한 객체를 설계하기 보다 훌륭한 협력을 설계해라.
  • 객체가 메시지를 선택하기 보다 메시지가 객체를 선택하게 해라.
  • 인터페이스와 구현을 분리해라.

생각

책에서 전하고자 하는 메시지가 뇌리에 박힌다.
또한 부록에서 이책에서 언급할줄은 몰랐던 서브타이핑, 서브클래싱, 합성에 대해서도
언급하고 있는데 이것까지 다루기엔 책이 지향하는바를 넘어서는거 같아서 부록에 담은것 같다.

끝으로 객체지향에 대한 감을 잡는데 이 책은 괜찮은 책인거 같다.



http://www.yes24.com/Product/Goods/18249021

0개의 댓글