Skip to content

Latest commit

Β 

History

History
375 lines (258 loc) Β· 18.7 KB

File metadata and controls

375 lines (258 loc) Β· 18.7 KB

item 23 : νƒœκ·Έ 달린 ν΄λž˜μŠ€λ³΄λ‹€λŠ” 클래슀 계측ꡬ쑰λ₯Ό ν™œμš©ν•˜λΌ

1. νƒœκ·Έ 달린 클래슀

{% hint style="danger" %} νƒœκ·Έ 달린 ν΄λž˜μŠ€λŠ” ν•˜λ‚˜μ˜ ν΄λž˜μŠ€μ—μ„œ μ—¬λŸ¬ 가지 λ‹€λ₯Έ νƒ€μž…μ˜ 객체λ₯Ό μ²˜λ¦¬ν•˜λŠ” λ°©μ‹μœΌλ‘œ μ„€κ³„λœλ‹€. ν•˜μ§€λ§Œ μ΄λ ‡κ²Œ ν•˜λ©΄ μ“Έλͺ¨μ—†λŠ” 데이터 ν•„λ“œμ™€ μ½”λ“œκ°€ 생기며, μœ μ§€λ³΄μˆ˜λ„ μ–΄λ ΅κ³  μ‹€μˆ˜λ‘œ 인해 λŸ°νƒ€μž„ 였λ₯˜κ°€ λ°œμƒν•  κ°€λŠ₯성도 컀진닀. {% endhint %}

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);
        }
    }
}
  • λΆˆν•„μš”ν•œ ν•„λ“œ: 각 λ„ν˜•μ— ν•„μš”ν•˜μ§€ μ•Šμ€ ν•„λ“œλ„ ν΄λž˜μŠ€μ— ν¬ν•¨λ˜μ–΄ μžˆλ‹€. 예λ₯Ό λ“€μ–΄, μ›μ—λŠ” length, widthκ°€ ν•„μš”ν•˜μ§€ μ•Šκ³ , μ‚¬κ°ν˜•μ—λŠ” radiusκ°€ ν•„μš” μ—†λ‹€.
  • 쑰건문으둜 λΆ„κΈ° 처리: νƒœκ·Έ 값에 따라 area() λ©”μ„œλ“œμ—μ„œ 쑰건문을 μ‚¬μš©ν•΄ λΆ„κΈ° μ²˜λ¦¬ν•˜λŠ” 방식은 λ³΅μž‘ν•˜κ³  μ‹€μˆ˜λ₯Ό μœ λ°œν•  수 μžˆλ‹€.
  • ν™•μž₯μ„± λΆ€μ‘±: μƒˆλ‘œμš΄ λ„ν˜•μ„ μΆ”κ°€ν•˜λ €λ©΄ switch 문에 μƒˆλ‘œμš΄ caseλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•˜λ©°, νƒœκ·Έ 값을 μ²˜λ¦¬ν•  수 μžˆλŠ” μ½”λ“œλ„ μΆ”κ°€ν•΄μ•Ό ν•œλ‹€.

1) νƒœκ·Έ 달린 ν΄λž˜μŠ€λž€?

클래슀 내뢀에 νŠΉμ • νƒœκ·Έ ν•„λ“œλ₯Ό 두고, κ·Έ νƒœκ·Έμ˜ 값에 따라 클래슀의 λ™μž‘μ΄λ‚˜ 데이터λ₯Ό λ‹€λ₯΄κ²Œ μ²˜λ¦¬ν•˜λŠ” λ°©μ‹μœΌλ‘œ μ„€κ³„λœ 클래슀λ₯Ό μ˜λ―Έν•œλ‹€. νƒœκ·Έ ν•„λ“œλŠ” 클래슀의 μƒνƒœλ‚˜ λͺ¨μ–‘을 λ‚˜νƒ€λ‚΄λŠ” 역할을 ν•œλ‹€. 이 νƒœκ·Έ ν•„λ“œμ— 따라 ν΄λž˜μŠ€κ°€ μ–΄λ–€ λ°©μ‹μœΌλ‘œ λ™μž‘ν• μ§€ κ²°μ •ν•˜λŠ”λ°, 예λ₯Ό λ“€μ–΄ ν΄λž˜μŠ€κ°€ μ—¬λŸ¬ 가지 λ‹€λ₯Έ νƒ€μž…μ˜ 객체λ₯Ό ν‘œν˜„ν•΄μ•Ό ν•˜λŠ” μƒν™©μ—μ„œ νƒœκ·Έ ν•„λ“œλ₯Ό μ‚¬μš©ν•΄ κ·Έ νƒ€μž…μ„ κ΅¬λΆ„ν•˜κ²Œ λ˜λŠ” κ²ƒμž„.

2) νƒœκ·Έ 달린 클래슀의 단점

  • μ—΄κ±° νƒ€μž… μ„ μ–Έ, νƒœκ·Έ ν•„λ“œ, switch λ¬Έ λ“± μ“Έλ°μ—†λŠ” μ½”λ“œκ°€ λ§Žλ‹€. μ—¬λŸ¬ κ΅¬ν˜„μ΄ ν•œ ν΄λž˜μŠ€μ— ν˜Όν•©λΌ μžˆμ–΄μ„œ 가독성도 λ‚˜μ˜λ‹€.
  • λ‹€λ₯Έ 의미λ₯Ό μœ„ν•œ μ½”λ“œλ„ μ–Έμ œλ‚˜ ν•¨κ»˜ ν•˜λ‹ˆ λ©”λͺ¨λ¦¬λ„ 많이 μ‚¬μš©ν•œλ‹€. ν•„λ“œλ“€μ„ final둜 μ„ μ–Έν•˜λ €λ©΄ ν•΄λ‹Ή μ˜λ―Έμ— 쓰이지 μ•ŠλŠ” ν•„λ“œλ“€κΉŒμ§€ μƒμ„±μžμ—μ„œ μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•œλ‹€(쓰지 μ•ŠλŠ” ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” λΆˆν•„μš”ν•œ μ½”λ“œκ°€ λŠ˜μ–΄λ‚œλ‹€).
  • 또 λ‹€λ₯Έ 의미λ₯Ό μΆ”κ°€ν•˜λ €λ©΄ μ½”λ“œ λ₯Ό μˆ˜μ •ν•΄μ•Ό ν•œλ‹€. 예λ₯Ό λ“€μ–΄ μƒˆλ‘œμš΄ 의미λ₯Ό μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ λͺ¨λ“  switch 문을 μ°Ύμ•„ μƒˆ 의미λ₯Ό μ²˜λ¦¬ν•˜λŠ” μ½”λ“œλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•˜λŠ”λ° , ν•˜λ‚˜λΌλ„ 빠뜨리면 μ—­μ‹œ λŸ°νƒ€μž„μ— λ¬Έμ œκ°€ 뢈거져 λ‚˜μ˜¬ 것이닀.
  • λ§ˆμ§€λ§‰μœΌλ‘œ, μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…λ§ŒμœΌλ‘œλŠ” ν˜„μž¬ λ‚˜νƒ€λ‚΄λŠ” 의미λ₯Ό μ•Œ 길이 μ „ν˜€ μ—†λ‹€.

ν•œλ§ˆλ””λ‘œ, νƒœκ·Έ 달린 ν΄λž˜μŠ€λŠ” μž₯ν™©ν•˜κ³ , 였λ₯˜λ₯Ό λ‚΄κΈ° 쉽고, λΉ„νš¨μœ¨μ μ΄λ‹€.

2. μ„œλΈŒνƒ€μ΄ν•‘ (subtyping) : 클래슀 계측 ꡬ쑰λ₯Ό μ΄μš©ν•œ ν•΄κ²° 방법

λ‹€ν–‰νžˆ μžλ°”μ™€ 같은 객체 지ν–₯ μ–Έμ–΄λŠ” νƒ€μž… ν•˜λ‚˜λ‘œ λ‹€μ–‘ν•œ 의미의 객체λ₯Ό ν‘œν˜„ν•˜λŠ” 훨씬 λ‚˜μ€ μˆ˜λ‹¨μ„ μ œκ³΅ν•œλ‹€.

λ°”λ‘œ 클래슀 계측ꡬ쑰λ₯Ό ν™œμš©ν•˜λŠ” μ„œλΈŒνƒ€μ΄ν•‘ (subtyping)이닀.

클래슀λ₯Ό κ³„μΈ΅κ΅¬μ‘°λ‘œ μ„€κ³„ν•˜λ©΄ λœλ‹€. κ°€μž₯ λ¨Όμ € 루트 클래슀둜 좔상 클래슀λ₯Ό μ •μ˜ν•˜κ³ , νƒœκ·Έμ— 따라 λ‹¬λΌμ§€λŠ” λ©”μ„œλ“œλ₯Ό 좔상 λ©”μ„œλ“œλ‘œ μ„ μ–Έν•œλ‹€. 그런 λ‹€μŒ 각 λ„ν˜•μ— ν•΄λ‹Ήν•˜λŠ” ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€μ–΄ 각각의 ν•„λ“œλ₯Ό κ°€μ§€κ²Œ ν•˜κ³ , 루트 클래슀의 좔상 λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€.

1) 클래슀 계측 ꡬ쑰둜 ν•œ μ½”λ“œ

// 루트 클래슀: λͺ¨λ“  λ„ν˜•μ˜ 곡톡 쑰상
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;
    }
}

2) 클래슀 κ³„μΈ΅κ΅¬μ‘°μ˜ μž₯점

  • λΆˆν•„μš”ν•œ ν•„λ“œ 제거: 각 λ„ν˜•μ— λ§žλŠ” ν•„λ“œλ§Œ 남기고 λΆˆν•„μš”ν•œ ν•„λ“œλŠ” λͺ¨λ‘ μ œκ±°ν–ˆλ‹€.
  • λΆ„κΈ° 처리 제거: 쑰건문을 μ‚¬μš©ν•œ λΆ„κΈ° μ²˜λ¦¬κ°€ ν•„μš” μ—†λ‹€. 각 λ„ν˜• ν΄λž˜μŠ€μ—μ„œ κ³ μœ ν•œ λ‘œμ§μ„ κ΅¬ν˜„ν•  수 μžˆμ–΄ μ½”λ“œλ₯Ό κ°„κ²°ν•˜κ²Œ μœ μ§€ν•  수 μžˆλ‹€.
  • μœ μ—°ν•œ ν™•μž₯μ„±: μƒˆλ‘œμš΄ λ„ν˜•μ„ μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ 루트 클래슀λ₯Ό κ±΄λ“œλ¦΄ ν•„μš” 없이 독립적인 ν•˜μœ„ 클래슀λ₯Ό μΆ”κ°€ν•˜λ©΄ λœλ‹€.
  • 컴파일 νƒ€μž„ 검증: μ»΄νŒŒμΌλŸ¬κ°€ 각 ν΄λž˜μŠ€κ°€ ν•„μš”ν•œ ν•„λ“œλ₯Ό λͺ¨λ‘ μ΄ˆκΈ°ν™”ν•˜κ³ , 좔상 λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν–ˆλŠ”μ§€ 확인해쀀닀. λ”°λΌμ„œ μ‹€μˆ˜λ‘œ μΈν•œ λŸ°νƒ€μž„ 였λ₯˜κ°€ 쀄어든닀.

3) 좔가적인 ν™•μž₯ (μ •μ‚¬κ°ν˜• μ˜ˆμ‹œ)

계측 ꡬ쑰둜 μ„€κ³„ν–ˆμ„ 경우, μƒˆλ‘œμš΄ λ„ν˜•μ„ μ‰½κ²Œ ν™•μž₯ν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, μ •μ‚¬κ°ν˜•μ„ μ‚¬κ°ν˜•μ˜ νŠΉλ³„ν•œ ν˜•νƒœλ‘œ μ •μ˜ν•  수 μžˆλ‹€.

class Square extends Rectangle {
    Square(double side) {
        super(side, side);  // μ •μ‚¬κ°ν˜•μ€ 길이와 λ„ˆλΉ„κ°€ 동일
    }
}

3. 좔상 클래슀λ₯Ό μ“°λŠ” λ•Œ

μ•„μ΄ν…œ 20μ—μ„œλŠ” μΆ”μƒν΄λž˜μŠ€λ³΄λ‹€λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ³ λ €ν•˜λΌκ³  ν–ˆλŠ”λ°..? μ™œ μœ„μ— 계측 ꡬ쑰일 λ•ŒλŠ” μΆ”μƒν΄λž˜μŠ€λ₯Ό μ΄μš©ν•œ 걸까? πŸ€”

좔상 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” 상황에 따라 λ‹€λ₯΄λ‹€. μœ„μ—μ„œ μΈν„°νŽ˜μ΄μŠ€κ°€ 더 μœ μ—°ν•˜κ³  닀쀑 상속이 κ°€λŠ₯ν•˜λ‹€κ³  ν–ˆμ§€λ§Œ, 좔상 ν΄λž˜μŠ€κ°€ ν•„μš”ν•œ κ²½μš°λ„ μžˆλ‹€. 좔상 클래슀λ₯Ό μ„ νƒν•˜λŠ” μ£Όμš” 이유λ₯Ό λͺ‡ 가지 μ„€λͺ…ν•΄λ³΄μž

1) 곡톡 μƒνƒœλ‚˜ κ΅¬ν˜„μ΄ ν•„μš”ν•  λ•Œ

좔상 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” κ°€μž₯ 큰 μ΄μœ λŠ” 곡톡 μƒνƒœ(ν•„λ“œ)λ₯Ό κ³΅μœ ν•˜κ±°λ‚˜ κΈ°λ³Έ κ΅¬ν˜„μ„ μ œκ³΅ν•˜κΈ° μœ„ν•΄μ„œμ΄λ‹€.

예λ₯Ό λ“€μ–΄, μ—¬λŸ¬ μ„œλΈŒ ν΄λž˜μŠ€λ“€μ΄ κ³΅ν†΅μ μœΌλ‘œ μ‚¬μš©ν•  μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ‚˜ λ©”μ„œλ“œκ°€ μžˆλ‹€λ©΄, 좔상 클래슀둜 이 뢀뢄을 상속받아 μ‚¬μš©ν•˜κ²Œ ν•  수 μžˆλ‹€.

  • μ˜ˆμ‹œ: λͺ¨λ“  λ„ν˜• ν΄λž˜μŠ€μ—μ„œ μƒ‰κΉ”μ΄λ‚˜ μœ„μΉ˜ λ“±μ˜ 곡톡 ν•„λ“œλ₯Ό μœ μ§€ν•˜κ³  μ‹Άλ‹€λ©΄, 좔상 ν΄λž˜μŠ€κ°€ μ ν•©ν•˜λ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ κ³΅ν†΅λœ μƒνƒœλ₯Ό 상속받아 μ‚¬μš©ν•  수 있고, μ½”λ“œ 쀑볡을 쀄일 수 μžˆλ‹€.
abstract class Shape {
    String color;  // 곡톡 μƒνƒœ (ν•„λ“œ)
    
    // 곡톡 κ΅¬ν˜„μ„ μœ„ν•œ λ©”μ„œλ“œ
    void setColor(String color) {
        this.color = color;
    }

    abstract double area();  // μ„œλΈŒ ν΄λž˜μŠ€κ°€ κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” 좔상 λ©”μ„œλ“œ
}

이 경우 λͺ¨λ“  λ„ν˜•μ€ 색깔을 κ°–κ³  있고, 색깔을 λ³€κ²½ν•  수 μžˆλ‹€. 이 κΈ°λŠ₯을 λͺ¨λ“  λ„ν˜• μ„œλΈŒ ν΄λž˜μŠ€μ— 일일이 κ΅¬ν˜„ν•˜λŠ” λŒ€μ‹ , 좔상 클래슀λ₯Ό 톡해 κ³΅ν†΅μœΌλ‘œ μƒμ†λ°›λŠ”λ‹€.

2) κ³΅ν†΅λœ 행동(λ©”μ„œλ“œ)을 μ •μ˜ν•  λ•Œ

μΈν„°νŽ˜μ΄μŠ€λŠ” μƒνƒœ(ν•„λ“œ)λ₯Ό κ°€μ§ˆ 수 μ—†κ³ , λ©”μ„œλ“œμ˜ κΈ°λ³Έ κ΅¬ν˜„μ„ μ œκ³΅ν•  수 μžˆλŠ” λ””ν΄νŠΈ λ©”μ„œλ“œλ„ 일뢀 μ œν•œμ μ΄λ‹€. ν•˜μ§€λ§Œ 좔상 ν΄λž˜μŠ€λŠ” μƒμ†λ°›λŠ” ν΄λž˜μŠ€μ— κΈ°λ³Έ λ©”μ„œλ“œ κ΅¬ν˜„μ„ μ œκ³΅ν•  수 μžˆλ‹€.

예λ₯Ό λ“€μ–΄, λ„ν˜• ν΄λž˜μŠ€μ—μ„œ 면적을 κ΅¬ν•˜λŠ” area() λ©”μ„œλ“œλŠ” 각 λ„ν˜•λ§ˆλ‹€ λ‹€λ₯΄κ²Œ κ΅¬ν˜„λ˜κ² μ§€λ§Œ, toString() 같은 곡톡적인 λ™μž‘μ€ 좔상 ν΄λž˜μŠ€μ—μ„œ 미리 μ •μ˜ν•΄μ€„ 수 μžˆλ‹€.

abstract class Shape {
    abstract double area();

    @Override
    public String toString() {
        return "This is a shape";
    }
}

λͺ¨λ“  λ„ν˜• μ„œλΈŒ ν΄λž˜μŠ€λŠ” toString() λ©”μ„œλ“œλ₯Ό μžλ™μœΌλ‘œ 상속받아 μ‚¬μš©ν•  수 있게 λœλ‹€. λ§Œμ•½ μΈν„°νŽ˜μ΄μŠ€μ˜€λ‹€λ©΄ 이런 곡톡적인 κ΅¬ν˜„μ„ μ œκ³΅ν•˜κΈ°κ°€ μ–΄λ ΅λ‹€.

3) μƒμ†μ˜ νŽΈλ¦¬ν•¨

좔상 ν΄λž˜μŠ€λŠ” μƒμ†λ°›λŠ” ν΄λž˜μŠ€λ“€μ΄ μžλ™μœΌλ‘œ κΈ°λ³Έ κ΅¬ν˜„μ„ κ°€μ§€κ²Œ ν•˜κ³ , ν•„μš”ν•œ λΆ€λΆ„λ§Œ μ˜€λ²„λΌμ΄λ“œν•  수 있게 도와쀀닀. μ΄λŠ” μ½”λ“œ 쀑볡을 쀄이고, μΌκ΄€λœ λ°©μ‹μœΌλ‘œ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” 데 μœ λ¦¬ν•˜λ‹€.

예λ₯Ό λ“€μ–΄, μžλ°”μ˜ AbstractList, AbstractMap 같은 좔상 ν΄λž˜μŠ€λŠ” λͺ¨λ“  λ¦¬μŠ€νŠΈλ‚˜ 맡 κ΅¬ν˜„μ²΄κ°€ κ³΅ν†΅μ μœΌλ‘œ μ‚¬μš©ν•˜λŠ” λ©”μ„œλ“œλ₯Ό 미리 μ •μ˜ν•˜κ³ , 각 κ΅¬ν˜„μ²΄λŠ” κ·Έ λ©”μ„œλ“œλ₯Ό 상속받아 μ‚¬μš©ν•  수 μžˆλ‹€. μ΄λŠ” ꡬ체적인 κ΅¬ν˜„μ„ κ°„νŽΈν•˜κ²Œ λ§Œλ“€ 수 있게 ν•΄μ€€λ‹€.

4) μ œν•œλœ 상속

좔상 ν΄λž˜μŠ€λŠ” 클래슀 계측ꡬ쑰 λ‚΄μ—μ„œ μ’€ 더 μ—„κ²©ν•˜κ²Œ 상속을 μ œν•œν•˜κ³ μž ν•  λ•Œ μ‚¬μš©λœλ‹€. μΈν„°νŽ˜μ΄μŠ€λŠ” 아무 ν΄λž˜μŠ€λ‚˜ κ΅¬ν˜„ν•  수 μžˆμ§€λ§Œ, 좔상 ν΄λž˜μŠ€λŠ” ν•˜λ‚˜μ˜ λΆ€λͺ¨ 클래슀만 상속할 수 있기 λ•Œλ¬Έμ—, μΌκ΄€λœ 계측ꡬ쑰λ₯Ό μœ μ§€ν•˜κ³  싢을 λ•Œ μ‚¬μš©λœλ‹€.

예λ₯Ό λ“€μ–΄, ShapeλΌλŠ” 좔상 ν΄λž˜μŠ€κ°€ μžˆλ‹€λ©΄, 이 좔상 클래슀λ₯Ό 상속받은 Circle, Rectangle 등은 λͺ¨λ‘ 같은 상속 ꡬ쑰λ₯Ό κ³΅μœ ν•˜κ²Œ λœλ‹€. μ΄λŠ” μ½”λ“œ μœ μ§€λ³΄μˆ˜μ„±κ³Ό 일관성을 λ†’μ΄λŠ” 데 κΈ°μ—¬ν•  수 μžˆλ‹€.

5) 곡톡 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μœ„ν•œ 골격 κ΅¬ν˜„ 제곡

좔상 ν΄λž˜μŠ€λŠ” μΈν„°νŽ˜μ΄μŠ€μ™€ ν•¨κ»˜ 골격 κ΅¬ν˜„(Skeletal Implementation)을 μ œκ³΅ν•˜λŠ” 데 맀우 μœ μš©ν•˜λ‹€.

즉, μΈν„°νŽ˜μ΄μŠ€λ‘œλŠ” νƒ€μž…μ„ μ •μ˜ν•˜κ³ , 좔상 ν΄λž˜μŠ€λ‘œλŠ” κΈ°λ³Έ λ™μž‘μ„ μ •μ˜ν•΄μ„œ, μ„œλΈŒ ν΄λž˜μŠ€λŠ” ν•„μš”ν•œ λΆ€λΆ„λ§Œ κ΅¬ν˜„ν•˜λ©΄ λœλ‹€.

예λ₯Ό λ“€μ–΄, μžλ°”μ˜ AbstractListλŠ” List μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 좔상 클래슀둜, List의 λ§Žμ€ λ©”μ„œλ“œλ₯Ό 기본적으둜 κ΅¬ν˜„ν•˜κ³  μžˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ μƒˆλ‘œμš΄ List κ΅¬ν˜„μ²΄λ₯Ό λ§Œλ“€ λ•Œ, AbstractListλ₯Ό μƒμ†λ°›μ•„μ„œ νŽΈλ¦¬ν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.

abstract class AbstractList<E> implements List<E> {
    @Override
    public boolean isEmpty() {
        return size() == 0;
    }
    
    @Override
    public boolean contains(Object o) {
        for (E e : this) {
            if (e.equals(o)) return true;
        }
        return false;
    }
    
    // 더 λ§Žμ€ λ©”μ„œλ“œλ₯Ό κΈ°λ³Έ κ΅¬ν˜„μœΌλ‘œ 제곡
}

이 방식은 μƒˆλ‘œμš΄ List κ΅¬ν˜„μ²΄λ₯Ό λ§Œλ“€ λ•Œ, 핡심 λ©”μ„œλ“œλ§Œ κ΅¬ν˜„ν•˜κ³  λ‚˜λ¨Έμ§€λŠ” μžλ™μœΌλ‘œ 상속받을 수 있게 ν•΄μ€€λ‹ˆλ‹€.

κ²°λ‘ : μ™œ 좔상 클래슀λ₯Ό μ‚¬μš©ν•˜λ‚˜?

μΈν„°νŽ˜μ΄μŠ€κ°€ 더 μœ μ—°ν•˜κ³  닀쀑 상속이 κ°€λŠ₯ν•˜λ”λΌλ„, 곡톡 μƒνƒœ(ν•„λ“œ)λ₯Ό κ³΅μœ ν•˜κ±°λ‚˜ κΈ°λ³Έ λ™μž‘μ„ μ œκ³΅ν•΄μ•Ό ν•˜λŠ” μƒν™©μ—μ„œλŠ” 좔상 ν΄λž˜μŠ€κ°€ 더 μ ν•©ν•˜λ‹€. 특히 κ³΅ν†΅λœ λ°μ΄ν„°λ‚˜ κ΅¬ν˜„μ„ μƒμ†ν•˜κ³ , μ—¬λŸ¬ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ κ³΅ν†΅μ μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 곡톡 λ™μž‘μ„ μœ μ§€ν•΄μ•Ό ν•  λ•ŒλŠ” 좔상 ν΄λž˜μŠ€κ°€ 더 μ ν•©ν•œ 선택이 λœλ‹€.

결둠적으둜, 상황에 따라 좔상 ν΄λž˜μŠ€κ°€ 더 적합할 λ•Œκ°€ 있고, 이런 경우라면 좔상 클래슀λ₯Ό μ„ νƒν•˜λŠ” 것이 μ’‹λ‹€.

4. μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν†΅ν•œ μ„œλΈŒνƒ€μ΄ν•‘

{% hint style="info" %} μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•œ 계측 ꡬ쑰도 μ„œλΈŒνƒ€μ΄ν•‘(subtyping)이라고 ν•  수 μžˆλ‹€. {% endhint %}

μ„œλΈŒνƒ€μ΄ν•‘μ€ 객체 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ ν•˜μœ„ νƒ€μž…(subtype)이 μƒμœ„ νƒ€μž…(supertype)의 역할을 ν•  수 μžˆλŠ” 관계λ₯Ό μ˜λ―Έν•œλ‹€.

즉, μƒμœ„ νƒ€μž…μ˜ λ©”μ„œλ“œλ₯Ό ν•˜μœ„ νƒ€μž…μ΄ λͺ¨λ‘ κ΅¬ν˜„ν•΄μ„œ ν•˜μœ„ νƒ€μž… 객체가 μƒμœ„ νƒ€μž…μœΌλ‘œ λ™μž‘ν•  수 μžˆλŠ” 상황을 λ§ν•©λ‹ˆλ‹€.

1) μ„œλΈŒνƒ€μ΄ν•‘κ³Ό μΈν„°νŽ˜μ΄μŠ€

μ„œλΈŒνƒ€μ΄ν•‘μ˜ 핡심은 "ν•˜μœ„ νƒ€μž…μ΄ μƒμœ„ νƒ€μž…μ˜ λͺ¨λ“  λ™μž‘μ„ 지원해야 ν•œλ‹€"λŠ” 점이닀. μΈν„°νŽ˜μ΄μŠ€λŠ” 이 μ„œλΈŒνƒ€μ΄ν•‘μ˜ κ·œμΉ™μ„ λ”°λ₯΄λŠ” λŒ€ν‘œμ μΈ μˆ˜λ‹¨ 쀑 ν•˜λ‚˜μ΄λ‹€. μΈν„°νŽ˜μ΄μŠ€λŠ” ν΄λž˜μŠ€κ°€ λ°˜λ“œμ‹œ κ΅¬ν˜„ν•΄μ•Ό ν•  λ©”μ„œλ“œλ“€μ˜ 집합을 μ •μ˜ν•˜λ―€λ‘œ, κ·Έ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ν΄λž˜μŠ€λ“€μ€ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ μ°Έμ‘°ν•  수 μžˆλ‹€.

즉, μΈν„°νŽ˜μ΄μŠ€λ₯Ό 기반으둜 계측 ꡬ쑰λ₯Ό λ§Œλ“€λ©΄, μƒμœ„ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ„ κ΅¬ν˜„ν•œ ν•˜μœ„ ν΄λž˜μŠ€κ°€ μƒμœ„ μΈν„°νŽ˜μ΄μŠ€λ‘œ λ™μž‘ν•  수 있기 λ•Œλ¬Έμ—, 이것도 μ„œλΈŒνƒ€μ΄ν•‘μ— ν•΄λ‹Ήν•œλ‹€.

μ˜ˆμ‹œ

interface Shape {
    double area(); // λͺ¨λ“  λ„ν˜•μ΄ κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” λ©”μ„œλ“œ
}

class Circle implements Shape {
    private double radius;

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

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

class Rectangle implements Shape {
    private double length;
    private double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    public double area() {
        return length * width;
    }
}

public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(4, 6);

        System.out.println("Circle Area: " + circle.area());
        System.out.println("Rectangle Area: " + rectangle.area());
    }
}

μœ„ μ½”λ“œμ—μ„œ ShapeλŠ” μΈν„°νŽ˜μ΄μŠ€μ΄κ³ , Circleκ³Ό Rectangle은 Shape μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ν΄λž˜μŠ€λ“€μ΄λ‹€. Circleκ³Ό Rectangle κ°μ²΄λŠ” λͺ¨λ‘ Shape νƒ€μž…μœΌλ‘œ 참쑰될 수 있고, Shape μΈν„°νŽ˜μ΄μŠ€μ— μ •μ˜λœ area() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. 이것이 λ°”λ‘œ μ„œλΈŒνƒ€μ΄ν•‘

2) 좔상 클래슀 vs μΈν„°νŽ˜μ΄μŠ€: μ„œλΈŒνƒ€μ΄ν•‘ 관점

  • 좔상 ν΄λž˜μŠ€λŠ” κ³΅ν†΅λœ μƒνƒœ(ν•„λ“œ)와 κ΅¬ν˜„μ„ κ³΅μœ ν•˜λŠ” 데 강점이 μžˆμ§€λ§Œ, 단일 μƒμ†λ§Œ κ°€λŠ₯ν•˜λ‹€. 즉, ν•œ ν΄λž˜μŠ€κ°€ ν•˜λ‚˜μ˜ λΆ€λͺ¨ 좔상 클래슀만 κ°€μ§ˆ 수 μžˆλ‹€.
  • μΈν„°νŽ˜μ΄μŠ€λŠ” μƒνƒœλ₯Ό κ°€μ§ˆ 수 μ—†μ§€λ§Œ, λ‹€μ–‘ν•œ κ΅¬ν˜„μ²΄κ°€ λ™μΌν•œ λ™μž‘μ„ 보μž₯ν•˜λ„λ‘ 닀쀑 상속이 κ°€λŠ₯ν•˜λ‹€. 즉, ν•˜λ‚˜μ˜ ν΄λž˜μŠ€κ°€ μ—¬λŸ¬ 개의 μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‘˜ λ‹€ μ„œλΈŒνƒ€μ΄ν•‘μ„ μ§€μ›ν•˜μ§€λ§Œ, μΈν„°νŽ˜μ΄μŠ€λŠ” 더 μœ μ—°ν•œ 계측 ꡬ쑰λ₯Ό 섀계할 수 있게 도와쀀닀.

{% hint style="success" %}

μ„œλΈŒνƒ€μ΄ν•‘μ€ μƒμœ„ νƒ€μž…(μΈν„°νŽ˜μ΄μŠ€λ‚˜ 좔상 클래슀)의 λ™μž‘μ„ ν•˜μœ„ νƒ€μž…μ΄ κ΅¬ν˜„ν•΄μ„œ μƒμœ„ νƒ€μž…μ²˜λŸΌ λ™μž‘ν•  수 μžˆλŠ” 관계λ₯Ό λ§ν•˜λ©°, μΈν„°νŽ˜μ΄μŠ€λŠ” μ„œλΈŒνƒ€μ΄ν•‘μ„ κ΅¬ν˜„ν•˜λŠ” μ€‘μš”ν•œ 방법 쀑 ν•˜λ‚˜μ΄λ‹€.

{% endhint %}

5. μŠ€ν„°λ””μ—μ„œ μΆ”κ°€ μ„€λͺ… : API SERVER APPLICATION μ—μ„œ Entityλ₯Ό 클래슀 κ³„μΈ΅κ΅¬μ‘°λ‘œ λ§Œλ“œλ €λ©΄

좜처 : https://antique-banon-928.notion.site/Effective-Java-20-25-10-17-11d82aee42598045ab1ded57b536635b

1) νΌμ‹œμŠ€ν„΄μŠ€ λ ˆμ΄μ–΄ ν™œμš©

νΌμ‹œμŠ€ν„΄μŠ€ λ ˆμ΄μ–΄μ—μ„œ λ‹¨μˆœνžˆ DB에 μ €μž₯λ˜μ–΄ μžˆλŠ” 값을 κΊΌλ‚΄μ˜€λŠ” μ—­ν• λ§Œ ν•˜μ§€ μ•Šκ³ , κ³„μΈ΅κ΅¬μ‘°μ˜ νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•΄μ£ΌλŠ” 역할을 ν•΄μ€€λ‹€.

λ ˆμ΄μ–΄λ“œ 아킀텍쳐

νΌμ‹œμŠ€ν„΄μŠ€ λ ˆμ΄μ–΄λ‘œ Repository, Dao Layer 총 λ‘κ³„μΈ΅μœΌλ‘œ λ‚˜λˆˆλ‹€.DaoλŠ” DBμ—μ„œ 값을 κΊΌλ‚΄μ˜€λŠ” 역할을, RepositoryλŠ” κ³„μΈ΅κ΅¬μ‘°μ˜ νƒ€μž…μœΌλ‘œ μ „ν™˜ν•΄μ£ΌλŠ” 역할을 λ§‘λŠ”λ‹€.

μ˜ˆμ‹œ

이미지 ν€΄μ¦ˆ, ν…μŠ€νŠΈ ν€΄μ¦ˆ 총 2 μ’…λ₯˜μ˜ ν€΄μ¦ˆκ°€ μ‘΄μž¬ν•œλ‹€.

Dao

  • QuizEntity νƒ€μž…κ°’μ„ κ°€μ§€κ²Œ 되기 λ•Œλ¬Έμ— 객체지ν–₯적으둜 μ’‹λ‹€λŠ” 것
@Repository
@RequiredArgsConstructor
public class QuizDao {

    private final JPAQueryFactory queryFactory;
    
    public List<QuizEntity> findQuiz(QuizType quizType) {
        return queryFactory
                .select(quiz)
                .from(quiz)
                .where(quiz.type.eq(quizType))
                .fetch();
    }
}

Repository

@Repository
@RequiredArgsConstructor
public class QuizRepository {

    private final QuizDao quizDao;

    public List<TextQuiz> findTextQuiz() {
        return quizDao.findQuiz(QuizType.TEXT)
                .map(TextQuiz::from).collect(Collectors.toList());
    }

    public List<ImageQuiz> findImageQuiz() {
        return quizDao.findQuiz(QuizType.IMAGE)
                .map(ImageQuiz::from).collect(Collectors.toList());
    }
}

✨ μ΅œμ’… 정리

  • νƒœκ·Έ 달린 클래슀λ₯Ό 써야 ν•˜λŠ” 상황은 거의 μ—†λ‹€. μƒˆλ‘œμš΄ 클래슀λ₯Ό μž‘μ„±ν•˜λŠ” 데 νƒœκ·Έν•„λ“œκ°€ λ“±μž₯ν•œλ‹€λ©΄ νƒœκ·Έλ₯Ό μ—†μ• κ³  κ³„μΈ΅κ΅¬μ‘°λ‘œ λŒ€μ²΄ν•˜λŠ” 방법을 μƒκ°ν•΄λ³΄μž.
  • 클래슀 κ³„μΈ΅κ΅¬μ‘°λ‘œ λ³€ν™˜ν•¨μœΌλ‘œμ¨ μ½”λ“œκ°€ 더 간결해지고, 각 클래슀의 역할이 λͺ…ν™•ν•΄μ‘Œλ‹€. νƒœκ·Έ 달린 ν΄λž˜μŠ€λŠ” μœ μ§€λ³΄μˆ˜μ™€ ν™•μž₯성이 λ–¨μ–΄μ§ˆ 수 μžˆμ§€λ§Œ, 클래슀 κ³„μΈ΅κ΅¬μ‘°λ‘œ λ³€ν™˜ν•˜λ©΄ μ΄λŸ¬ν•œ λ¬Έμ œλ“€μ„ ν•΄κ²°ν•  수 μžˆλ‹€.

κΈ°μ‘΄ ν΄λž˜μŠ€κ°€ νƒœκ·Έ ν•„λ“œλ₯Ό μ‚¬μš©ν•˜κ³  μžˆλ‹€λ©΄ κ³„μΈ΅κ΅¬μ‘°λ‘œ λ¦¬νŒ©ν„°λ§ν•˜λŠ” κ±Έ κ³ λ―Όν•΄λ³΄μž.