Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라

## 핵심 정리

- `상수를 정의하는 용도로 인터페이스를 사용하지 말 것!`
- `클래스 내부에서 사용할 상수는 내부 구현에 해당한다.`
- `내부 구현을 클래스의 API로 노출하는 행위가 된다.`
- `클라이언트에 혼란을 준다.`

```java
// 코드 22-1 상수 인터페이스 안티패턴 - 사용금지! (139쪽)
public interface PhysicalConstants {
// 아보가드로 수 (1/몰)
static final double AVOGADROS_NUMBER = 6.022_140_857e23;

// 볼츠만 상수 (J/K)
static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;

// 전자 질량 (kg)
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
```

- 인터페이스의 의도는 타입을 정의하는 것이다.
- `상수를 정의하는 방법`
- `특정 클래스나 인터페이스`
- `열거형`
- `인스턴스화 할 수 없는 유틸리티 클래스`

```java
// 코드 22-2 상수 유틸리티 클래스 (140쪽)
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;
}
```

- 최소한의 scope안에서 정의하는 것을 권장한다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라

## 핵심 정리

- `태그 달린 클래스의 단점`
- `쓸데없는 코드가 많다.`
- `가독성이 나쁘다.`
- `메모리도 많이 사용한다.`
- `필드를 final로 선언하려면 불필요한 필드까지 초기화해야 한다.`
- `인스턴스 타입만으로는 현재 나타내는 의미를 알 길이 없다.`

```java
// 코드 23-1 태그 달린 클래스 - 클래스 계층구조보다 훨씬 나쁘다! (142-143쪽)
class Figure {
enum Shape {RECTANGLE, CIRCLE, SQUARE}

// 태그 필드 - 현재 모양을 나타낸다.
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) {
if (this.length == this.width) {
shape = Shape.SQUARE;
} else {
shape = Shape.RECTANGLE;
}

this.length = length;
this.width = width;
}

double area() {
switch (shape) {
case RECTANGLE:
case SQUARE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError(shape);
}
}
}
```

- 태그 역할을 한다는 것은 shape와 같은 enum이 존재하는 것을 말한다.
- 위 코드의 경우 한 클래스에서 너무 많은 역할을 담당하고 있다.
- `클래스 계층 구조로 바꾸면 모든 단점을 해결할 수 있다.`

```java
abstract class Figure {
abstract double area();
}

// 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
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;
}
}

// 태그 달린 클래스를 클래스 계층구조로 변환 (145쪽)
class Square extends Rectangle {
Square(double side) {
super(side, side);
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# 아이템 24. 멤버 클래스는 되도록 static으로 만들라

## 핵심 정리

- `정적 멤버 클래스`
- `바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스.`
- `예) Calculator.Operation.PLUS`

```java
// 정적 멤버 클래스
public class OutterClass {

private static int number = 10;

static private class InnerClass {
void doSomething() {
System.out.println(number);
}
}

public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.doSomething();
}
}
```

- 내부 클래스가 외부 클래스의 참조를 가지고 있지 않는다.
- `비정적 멤버 클래스`
- `바깥 클래스의 인스턴스와 암묵적으로 연결된다.`
- `어댑터를 정의할 때 자주 쓰인다.`
- `멤버 클래스에서 바깥 인스턴스를 참조할 필요가 없다면 무조건 정적 멤버 클래스로 만들자.`

```java
public class OutterClass {
private int number = 10;

void printNumber() {
InnerClass innerClass = new InnerClass();
}

private class InnerClass {
void doSomething() {
System.out.println(number);
OutterClass.this.printNumber();
}
}

public static void main(String[] args) {
InnerClass innerClass = new OutterClass().new InnerClass();
innerClass.doSomething();
}
}
```

- InnerClass가 OutterClass의 참조를 가진다
- OutterClass가 생성된 후에 InnerClass를 생성할 수 있다.
- 불필요하게 OutterClass 생성 이후에 생성해야할지 고민해볼 필요가 있고 불필요하다면 정적 내부 클래스로 정의하는 것이 좋다.
- 외부 클래스의 참조가 없는 경우에 정적 내부 클래스로 정의하는 것을 권장한다.
- `익명 클래스`
- `바깥 클래스의 멤버가 아니며, 쓰이는 시점과 동시에 인스턴스가 만들어진다.`
- `비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있다.`
- `자바에서 람다를 지원하기 전에 즉석에서 작은 함수 객체나 처리 객체를 만들 때 사용했다.`
- `정적 팩터리 메서드를 만들 때 사용할 수도 있다.`

```java
// 코드 20-1 골격 구현을 사용해 완성한 구체 클래스 (133쪽)
public class IntArrays {
static List<Integer> intArrayAsList(int[] a) {
Objects.requireNonNull(a);

// 다이아몬드 연산자를 이렇게 사용하는 건 자바 9부터 가능하다.
// 더 낮은 버전을 사용한다면 <Integer>로 수정하자.
return new AbstractList<>() {
@Override
public Integer get(int i) {
return a[i]; // 오토박싱(아이템 6)
}

@Override
public Integer set(int i, Integer val) {
int oldVal = a[i];
a[i] = val; // 오토언박싱
return oldVal; // 오토박싱
}

@Override
public int size() {
return a.length;
}
};
}

public static void main(String[] args) {
int[] a = new int[10];
for (int i = 0; i < a.length; i++)
a[i] = i;

List<Integer> list = intArrayAsList(a);
Collections.shuffle(list);
System.out.println(list);
}
}
```

- `지역 클래스`
- `가장 드물게 사용된다.`
- `지역 변수를 선언하는 곳이면 어디든 지역 클래스를 정의해 사용할 수 있다.`
- `가독성을 위해 짧게 작성해야 한다.`

```java
public class MyClass {
private int number = 10;

void doSomething() {
// 로컬 클래스
class LocalClass {
private void printNumber() {
System.out.println(number);
}
}

LocalClass localClass = new LocalClass();
localClass.printNumber();
}

public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.doSomething();
}
}
```

## 완벽 공략

### 완벽 공략 39. 어댑터 패턴

- `p147. 어댑터`

`기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴`

- `클라이언트가 사용하는 인터페이스를 따르지 않는 기존 코드를 재사용할 수 있게
해준다.`

```java
// 어댑터 클래스
public class MySet<E> extends AbstractSet<E> {
@Override
public Iterator<E> iterator() {
return new MyIterator();
}

@Override
public int size() {
return 0;
}

private class MyIterator implements Iterator<E> {

@Override
public boolean hasNext() {
return false;
}

@Override
public E next() {
return null;
}
}
}
```

**어댑터 패턴 사용 예시**

```java
public class AdapterInJava {

public static void main(String[] args) {
try (InputStream is = new FileInputStream("number.txt");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr)) {
while (reader.ready()) {
System.out.println(reader.readLine());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
```

# References

- spring 내부 클래스, 정적 내부 클래스의 빈 생성: [https://www.inflearn.com/questions/803187/학습-테스트-작성-시-정적-클래스-관련질문](https://www.inflearn.com/questions/803187/%ED%95%99%EC%8A%B5-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%9E%91%EC%84%B1-%EC%8B%9C-%EC%A0%95%EC%A0%81-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B4%80%EB%A0%A8%EC%A7%88%EB%AC%B8)
8 changes: 8 additions & 0 deletions src/main/java/item22/constantinterface/MyClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package item22.constantinterface;

public class MyClass implements PhysicalConstants {

public static void main(String[] args) {
System.out.println(BOLTZMANN_CONSTANT);
}
}
13 changes: 13 additions & 0 deletions src/main/java/item22/constantinterface/PhysicalConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package item22.constantinterface;

// 코드 22-1 상수 인터페이스 안티패턴 - 사용금지! (139쪽)
public interface PhysicalConstants {
// 아보가드로 수 (1/몰)
static final double AVOGADROS_NUMBER = 6.022_140_857e23;

// 볼츠만 상수 (J/K)
static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;

// 전자 질량 (kg)
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
16 changes: 16 additions & 0 deletions src/main/java/item22/constantutilityclass/PhysicalConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package item22.constantutilityclass;

// 코드 22-2 상수 유틸리티 클래스 (140쪽)
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;
}
10 changes: 10 additions & 0 deletions src/main/java/item23/hierarchy/Circle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package item23.hierarchy;

// 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
class Circle extends Figure {
final double radius;

Circle(double radius) { this.radius = radius; }

@Override double area() { return Math.PI * (radius * radius); }
}
6 changes: 6 additions & 0 deletions src/main/java/item23/hierarchy/Figure.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package item23.hierarchy;

// 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
abstract class Figure {
abstract double area();
}
Loading