HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🛁
공부기록
/
📚
책 정리
/
🌨️
2장 - Education
🌨️

2장 - Education

CH3

항상 인터페이스를 사용하자!

객체는 살아가는 유기체입니다. 이 객체는 다른 유기체들과 의사소통 하면서 그들의 작업을 지원하고, 다른 유기체들 역시 이 객체에게 도움을 줍니다. 객체들의 세계는 매우 사회적이면서 유대감이 높은 환경입니다.

결합도를 낮추자!

  • 설계를 시작하는 단계에서 각각의 객체가 어떤 일을 수행하고 다른 객체에게 어떤 서비스를 제공할 지 정확하게 알고있는 편이 낮기 때문에 결합이 유용합니다.
  • 하지만 애플리케이션의 서비스가 커지면서 수십개의 객체가 생겨나고 객체 사이의 강한 결합도가 심각한 문제로 발생됩니다.
  • 결합도 문제는 유지보수에 많은 영향을 미치게 됩니다.
유지보수를 가능하도록 만들기 위해서는 최선을 다해 객체를 분리해야 합니다. 기술적인 관점에서 객체분리란 상호작용하는 다른 객체를 수정하지 않고 해당 객체를 수정할 수 있도록 만들어야 합니다. 이를 가능하게 하는 가장 훌륭한 도구가 바로 interface 입니다!
public interface Cash { Cash multiply(float factor); }
  • Cash는 인터페이스 입니다. 우리의 객체가 다른 객체와 의사소통 하기위해 따라야 하는 계약 입니다.
public class DefaultCash implements Cash { private int dollars; public DefaultCash(int dollars) { this.dollars = dollars; } @Override public Cash multiply(float factor) { return new DefaultCash((int) (this.dollars * factor)); } }
  • 이렇게 구현할 수 있으며 실제 구현 대신 계약에 의존시키도록 하면 됩니다.
public class Employee { private Cash salary; }
  • Employee 클래스는 Cash 인터페이스의 구현 방법에 아무런 관심이 없습니다.
  • multiply() 메서드가 어떻게 동작하는지도 관심이 없습니다. 즉 동작 방식을 알지 못합니다.
  • 그대로 Cash인터페이스를 이용하면 Employee 클래스와 DefaultCash 클래스를 느슨하게 분리할 수 있다는 뜻을 가지고 있습니다.
  • 이제 DefaultCash 내부의 구현을 변경하거나 심지어 Cash 인터페이스의 구현체를 다른것으로 교체하더라도 아무런 영향을 받지 않습니다.

CH4

메서드 이름을 신중하게 선택하자 !

  • 빌더의 이름은 명사로 조정자의 이름은 동사로 짓자.

빌더

  • 빌더란 뭔가를 만들고 새로운 객체를 반환하는 메서드를 가리킵니다. 빌더는 항상 뭔가를 반환합니다. 빌더의 반환타입은 절대 void가 될 수 없습니다.
  • 이름은 항상 명사여야 합니다.
int pow(int base, int power); float speed(); String parsedCell(int x, int y);

CH6

불변 객체로 만들자 !

모든 클래스를 상태 변경이 불가능한 불변 클래스(immutable class)로 구현하면 유지보수성을 크게 향상시킬 수 있다.

불변성

  • 크기가 작고 응집력이 높으며 느슨하게 결합되고 유지보수하기 쉬운 클래스를 만들 수 있도록 해준다.
  • 가변 클래스보다는 불변 클래스를 이해하는 쪽이 훨씬 수월하다.
  • 불변 객체를 기반으로 사고하면 더 깔끔하고, 더 작고, 더 쉽게 이해할 수 있는 코드를 만들 수 있다.

불변객체란

  • 인스턴스를 생성한 후에 상태를 변경할 수 없는 객체를 불변객체라고 부른다.

그럼 가변 객체는 뭘까?

public class Cash { private int dollars; public void setDollars(int dollars) { this.dollars = dollars; } }
  • 위의 Cash클래스를 이용해서 생성한 객체는 상태 변경이 가능하기 때문에 가변 객체로 부른다.

불변 객체는 어떻게 생겼을까?

public class Cash { private final int dollars; Cash(int dollars) { this.dollars = dollars; } }
  • 가변 객체와 비슷하게 생겼지만 상태를 변경할 수 없는 불변 객체를 생성합니다.
  • 가변객체와 비교해서 달라진 부분은 final 키워드를 추가했다는 점 입니다.
  • final 키워드는 생성자 외부에서 프로퍼티 값을 수정할 경우 컴파일 타임 에러가 발생됩니다.
  • 불변객체는 필요한 모든 것을 내부에 캡슐화 하고 변경할 수 없도록 해야합니다. 불변객체를 수정해야 한다면 프로퍼티를 수정하는 대신 새로운 객체를 생성해야 합니다.

금액을 곱하는 예제 - 가변객체

public class Cash { private int dollars; public void mul(int factor) { this.dollars *= factor; } }

금액을 곱하는 예제 - 불변객

public class Cash { private int dollars; public Cash(int dollars) { this.dollars = dollars; } public Cash mul(int factor) { return new Cash(this.dollars * factor); } }
둘 사이의 명확한 차이점은 불변 객체는 어떤 방식으로든 자기 자신을 수정할 수 없으며 항상 원하는 상태를 가지는 새로운 객체를 생성해서 반환해야 합니다.

명확한 이해를 돕는 예제

// 가변객체를 사용한 경우 Cash five = new Cssh(5); five.mul(10); System.out.println(five) // 50 // 불변 객체를 사용할 경우 Cash five = new Cash(5); Cash fifty = five.mul(10); System.out.println(fifty) // 50
  • five객체를 생성하고 나면 five는 fifty가 될 수 없습니다. 5는 5일뿐입니다. 5는 생명이 다하는 순간까지 5입니다 항상!