티스토리 뷰
아이템 15 클래스와 멤버의 접근 권한을 최소화하라
정보 은닉의 장점
- 시스템 개발 속도를 높인다.
- 시스템 관리 비용을 낮춘다.
- 성능 최적화에 도움을 준다.
- 소프트웨어 재사용성을 높인다.
- 큰 시스템을 제작하는 난이도를 낮춘다.
* 시스템을 구성하는 컴포넌트들을 서로 독립시켜서 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있게 해준다.
정보은닉을 위한 다양한 장치 중 하나인 접근제어를 사용하는 기본 원칙은 모든 클래스와 멤버의 접근성을 가능한 좁히는 것이다.
클래스의 공개 API를 세심히 설계한 후, 그 외의 모든 멤버는 private로 만들자.
아이템 16 public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라
public 클래스라면 위 방식보다 아래 방식을 지향하도록 하자.
class Point {
public double x;
public double y;
}
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double x) { this.x = x; }
public void setY(double y) { this.y = y; }
}
아이템 17 변경 가능성을 최소화하라
클래스를 불변으로 만드려면 다음 다섯 가지 규칙을 따르면 된다.
- 객체의 상태를 변경하는 메서드(변경자, setter 등)를 제공하지 않는다.
- 클래스를 확장할 수 없도록 한다. 하위 클래스에서 부주의하게 혹은 나쁜 의도로 객체의 상태를 변하게 만드는 사태를 막아준다. 상속을 받는 대표적은 방법은 클래스를 final로 선언하는 것이다.
- 모든 필드를 final로 선언한다. 설계자의 의도를 명확히 드러내는 방법이다. 새로 생성된 인스턴스를 동기화 없이 다른 스레드로 건네도 문제없이 동작하게끔 보장하는 데도 필요하다.
- 모든 필드를 private으로 선언한다. 필드가 참조하는 가변 객체를 클라이언트가 직접 접근해 수정하는 일을 막아준다. public final으로 선언하면 다음 릴리스에서 내부 표현을 바꾸지 못하므로 private 선언이 더 좋을 수 있다.
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 클래스에 가변 객체를 참조하는 필드가 하나라도 있다면 클라이언트에서 그 객체의 참조를 얻을 수 없도록 해야 한다. 생성자, 접근자, readObject 메서드 모두에서 방어적 복사를 수행하라.
클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다.
성능 때문에 어쩔 수 없다면 불변 클래스와 쌍을 이루는 가변 동반 클래스를 고려하자. (String, StringBuilder)
확실한 이유가 없다면, 생성자와 정적 팩터리 외에는 그 어떤 매서드도 public으로 제공해서는 안 된다. (API가 아닌 객체 클래스에 관한 설명으로 보임)
아이템 18, 상속보다는 컴포지션을 사용하라
상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다.
위 문제를 피하기 위해 기존 클래스를 확장하는 대신 새로운 클래스를 만들고 private 필드로 기존 클래스의 인스턴스를 참조하게 하자.
기존 클래스가 새로운 클래스의 구성요소로 쓰인다는 뜻에서 이런 설계를 컴포지션(composition; 구성)이라고 한다.
*컴포지트 패턴 더 알아보기
https://ko.wikipedia.org/wiki/%EC%BB%B4%ED%8F%AC%EC%A7%80%ED%8A%B8_%ED%8C%A8%ED%84%B4
https://blog.seotory.com/post/2017/09/java-composite-pattern
새 클래스의 인스턴스 매서드들은 기존 클래스에 대응하는 메서드를 호출해 그 결과를 반환한다. 이런 방식을 전달(forwarding)이라고 하며, 새 클래스의 메서드들은 전달 메서드(forwarding method)라 부른다.
기존 클래스를 감싸고 있다는 뜻에서 위와 같은 전달 클래스를 래퍼 클래스라 하며, 기존 클래스에 기능을 덧씌운다는 뜻에서 데코레이터 패턴(Decorator pattern)이라고 한다.
*데코레이터 패턴 더 알아보기
https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0_%ED%8C%A8%ED%84%B4
https://coding-factory.tistory.com/713
아이템 19 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
널리 쓰일 클래스를 상속용으로 설계한다면 여러분이 문서화한 내부 사용 패턴과, protected 메서드와 필드를 구현하면서 선택한 결정에 영원히 책임져야 함을 잘 인식해야 한다.
이 결정들이 그 클래스의 성능과 기능에 영원한 족쇄가 될 수 있다. 그러니 상속용으로 설계한 클래스는 배포 전에 반드시 하위 클래스를 만들어 검증해야 한다.
클래스를 상속용으로 만들기 위해선 엄청난 노력이 들고 그 클래스에 안기는 제약도 상당하다.
이 문제를 해결하는 가장 좋은 방법은 상속용으로 설계하지 않은 클래스는 상속을 금지하는 것이다.
상속을 금지하는 방법은 두 가지다. 첫번째는 클래스를 final로 선언하는 방법이다. 두번째는 모든 생성자를 private나 package-private로 선언하고 public 정적 팩터리를 만들어주는 방법이다.
아이템 20 추상 클래스보다는 인터페이스를 우선하라
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스 이렇게 두가지다.
예를 들어 가수(Singer) 인터페이스와 작곡가(Songwriter) 인터페이스가 있다고 해보자.
public interface Singer {
AudioClip sing(Song s);
}
public interface Songwriter {
Song compose(int chartPosition);
}
위 코드처럼 타입을 인터페이스로 정의하면 가수 클래스가 singer와 songwriter 모두를 구현해도 전혀 문제되지 않는다.
public interface SingerSongwriter extends Singer, Songwriter {
AudioClip strum();
void actSensitive();
}
그러나 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다. 자바는 단일 상속만 지원하니 추상 클래스 방식은 새로운 타입을 정의하는데 커다란 제약을 안게 되는 셈이다.
템플릿 메서드 패턴
어댑터 패턴
https://ko.wikipedia.org/wiki/%EC%96%B4%EB%8C%91%ED%84%B0_%ED%8C%A8%ED%84%B4
디폴트 메서드(default method)
https://devfunny.tistory.com/350
아이템 22 인터페이스는 타입을 정의하는 용도로만 사용하라
인터페이스는 타입을 정의하는 용도로만 사용하고 상수를 공개하는 수단으로 사용하는건 지양하도록 하자.
만약 상수를 공개할 목적이라면 인스턴스화할 수 없는 유틸리티 클래스에 담아 공개하자.
public class PhysicalConstants {
private PhysicalConstants() { } // 인스턴스화 방지
// 아보가드로 수 (1/몰)
public static final double AVOGADROS_NUMBER = 6.022_140_857e23;
// 볼츠만 상수 (J/K)
public static final double BOLTZMANN_CONST = 1.380_648_52e-23;
// 전자 질량 (kg)
public static final double ELECTRON_MASS = 9.109_383_56e-31;
}
만약 유틸리티 클래스의 상수를 빈번히 사용하게 된다면 정적 임포트 (static import)하여 클래스 이름을 생략할 수 있다.
import static effectivejava.chapter4.item22.constantutilityclass.PhysicalConstants.*;
public class Test {
double atoms(double mols) {
return AVOGADROS_NUMBER * mols;
}
...
// PhysicalConstants를 빈번히 사용한다면 정적 임포트가 값어치를 한다.
}
아이템 23 태그 달린 클래스보다는 클래스 계층구조를 활용하라
class Figure {
enum Shape { RECTANGLE, CIRCLE };
// 태그 필드 - 현재 모양을 나타낸다.
final Shape shape;
// 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다.
double length;
double width;
// 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다.
double radius;
// 원용 생성자
Figure(double radius) {
shape = Shape.CIRCLE;
this.radius = radius;
}
// 사각형용 생성자
Figure(double length, double width) {
shape = Shape.RECTANGLE;
this.length = length;
this.width = width;
}
double area() {
switch(shape) {
case RECTANGLE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError(shape);
}
}
}
위 코드는 원과 사각형을 표현할 수 있는 클래스다.
한 클래스에 여러 구현이 혼합돼 있어서 가독성이 나쁘고 다른 의미를 위한 코드가 언제나 함께 하니 메모리도 많이 사용한다.
abstract class Figure {
abstract double area();
}
class Circle extends Figure {
final double radius;
Circle(double radius) { this.radius = radius; }
@Override double area() { return Math.PI * (radius * radius); }
}
class Rectangle extends Figure {
final double length;
final double width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override double area() { return length * width; }
}
위 코드 같이 계층 구조를 활용하도록하자.
아이템24 멤버 클래스는 되도록 static으로 만들라
중첩 클래스란 다른 클래스 안에 정의된 클래스를 말한다.
중첩 클래스의 종류는
- 정적 멤버 클래스
- (비정적) 멤버 클래스
- 익명 클래스
- 지역 클래스
이렇게 네 가지다.
이 중 첫 번째를 제외한 나머지는 내부 클래스(inner class)에 해당한다.
정적 멤버 클래스는 다른 클래스 안에 선언되고 바깥 클래스의 private 멤버에도 접근할 수 있다는 점만 제외하고는 일반 클래스와 똑같다.
'프로그래밍 > 책' 카테고리의 다른 글
[이펙티브 자바, Effeective Java] 7장 람다와 스트림 (0) | 2022.01.04 |
---|---|
[이펙티브 자바, Effeective Java] 6장 열거 타입과 어노테이션 (0) | 2021.12.28 |
[이펙티브 자바, Effeective Java] 5장 제네릭 (0) | 2021.12.22 |
[이펙티브 자바, Effeective Java] 3장 모든 객체의 공통 메서드 (1) | 2021.12.08 |
[이펙티브 자바, Effeective Java] 2장 객체 생성과 파괴 (1) | 2021.11.30 |
- Total
- Today
- Yesterday
- 오라클
- 깃허브 웹훅 젠킨스
- spring boot jenkins
- CI/CD
- github webhook jenkins
- nginx 톰캣 설정
- jenkins webhook
- 토이프로젝트 회고
- slack
- 국비 프로젝트
- springboot
- nginx to 내장톰캣
- 스프링부트 젠킨스
- 젠킨스 자동 배포
- spring boot
- 오라클 계정 오류
- springboot jpa
- github webhook
- GitHub
- nginx 내장톰캣 설정
- 젠킨스 웹훅
- 스프링부트 자동배포
- HTML
- nginx to springboot tomcat
- nginx 내장톰캣 연결
- webhook
- oracle
- nginx to tomcat
- oracle.jdbc.driver.T4CConnection.isValid(I)Z
- java.lang.AbstractMethodError
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |