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
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 16 additions & 0 deletions src/docs/week8/item22.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# item 22. 인터페이스는 타입을 정의하는 용도로만 사용하라.

1. 상수를 정의하는 용도로 인터페이스를 사용하지 말 것! (안티패턴)
- 인터페이스의 원래 의도인 "타입을 정의하는 것"을 오염시키기 때문에 안티패턴이다.
- 클래스 내부에서 사용할 상수는 내부 구현(클래스 내부 정보)에 해당한다.
- 내부 구현을 클래스의 API로 노출하는 행위가 된다.
- 인터페이스를 통해 외부에 노출됨
- 클라이언트에 혼란을 준다.
- 이 클래스가 인터페이스를 구현하고 있으면, "이 클래스가 이 인터페이스 타입이라는건가?", "`PysicalConstants myClass = new MyClass()` 이렇게 사용하라는건가?" 라며 혼란을 준다.

2. 상수를 정의하는 방법
- 특정 클래스나 인터페이스
- 인터페이스는 최대한 자제하자, 인터페이스는 클래스와 다르게 implements를 막을 방법이 없음
- 열거형
- 인스턴스화 할 수 없는 유틸리티 클래스

58 changes: 58 additions & 0 deletions src/docs/week8/item23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# item 23. 태그 달린 클래스보다는 클래스 계층 구조를 활용하라


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

2. 클래스 계층 구조로 바꾸면 모든 단점을 해결할 수 있다. (상속)


```java
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, SQUARE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError(shape);
}
}
}
```
- Shape가 Circle이지만, Rectangle과 관련된 필드, 메서드들을 가지고 있음
44 changes: 44 additions & 0 deletions src/docs/week8/item24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# item 24. 멤버 클래스는 되도록 static으로 만들라

1. 정적 멤버 클래스
- 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스. 예) Calculator.Operation.PLUS (Enum)
- Outter 클래스와 독립적이다.
- Outter 클래스를 참조하지 않는 경우에 사용한다.
- 참조하는 곳이 있다면, 비정적 멤버 클래스로 만들 수 밖에 없다.
- 비정적 멤버 클래스는 암뭄적으로 바깥 인스턴스에 대한 참조가 생긴다.
- 이 말은 즉슨, Outter class 인스턴스 없이는 자기 자신을 생성할 수 없다.
- `InnerClass innerClass = new OutterClass().new InnerClass();`

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

3. 익명 클래스
- 바깥 클래스의 멤버가 아니며, 쓰이는 시점과 동시에 인스턴스가 만들어진다.
- 비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있다.
- 자바에서 람다를 지원하기 전에 즉석에서 작은 함수 객체나 처리 객체를 만들 때 사용했다.
- 정적 팩터리 메서드를 만들 때 사용할 수도 있다.

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


#### 어댑터 패턴
기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴
- 클라이언트가 사용하는 인터페이스를 따르지 않는 기존 코드를 재사용할 수 있게 해준다.

```java
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);
}
```
- InputStream을 InputStreamReader로 사용할 수 있게끔
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.effectivejava3e.week8.item22.constantinterface;

public class MyClass implements PhysicalConstants {

public static void main(String[] args) {
System.out.println(BOLTZMANN_CONSTANT);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.effectivejava3e.week8.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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.effectivejava3e.week8.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;
}



Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.effectivejava3e.week8.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); }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.effectivejava3e.week8.item23.hierarchy;

// 코드 23-2 태그 달린 클래스를 클래스 계층구조로 변환 (144쪽)
abstract class Figure {
abstract double area();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.effectivejava3e.week8.item23.hierarchy;

// 코드 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; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.effectivejava3e.week8.item23.hierarchy;

// 태그 달린 클래스를 클래스 계층구조로 변환 (145쪽)
class Square extends Rectangle {
Square(double side) {
super(side, side);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.example.effectivejava3e.week8.item23.taggedclass;

// 코드 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, SQUARE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError(shape);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.effectivejava3e.week8.item24.adapter;

import java.io.*;
import java.util.*;

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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package me.whiteship.chapter04.item24.anonymousclass;

import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

// 코드 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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package me.whiteship.chapter04.item24.localclass;

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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.example.effectivejava3e.week8.item24.memberclass;

import java.util.AbstractSet;
import java.util.Iterator;

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;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.effectivejava3e.week8.item24.memberclass;

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();
}

}
Loading