๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
JAVA/Effective Java

Item23. ํƒœ๊ทธ ๋‹ฌ๋ฆฐ ํด๋ž˜์Šค๋ณด๋‹ค๋Š” ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ํ™œ์šฉํ•˜๋ผ

by ๋ฏผํœ˜ 2023. 6. 29.
๐Ÿ’ก ํƒœ๊ทธ ๋‹ฌ๋ฆฐ ํด๋ž˜์Šค๋Š” ์‘์ง‘๋„๊ฐ€ ๋‚ฎ๋‹ค. ์‘์ง‘๋„ ๋†’์€ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋กœ ์ชผ๊ฐœ์•ผ ํ•œ๋‹ค. ํด๋ž˜์Šค ๊ณ„์ธต๊ตฌ์กฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ์ƒ์†์„ ์‚ฌ์šฉํ•ด ์„œ๋ธŒํƒ€์ž…์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ผ.

 

ํƒœ๊ทธ ๋‹ฌ๋ฆฐ ํด๋ž˜์Šค

ํƒœ๊ทธ๋ž€, ๋‘ ๊ฐ€์ง€ ์ด์ƒ์˜ ์˜๋ฏธ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ์ด๋‹ค. ํƒœ๊ทธ ๋‹ฌ๋ฆฐ ํด๋ž˜์Šค๋Š” ํ˜„์žฌ ํ‘œํ˜„ํ•˜๋Š” ์˜๋ฏธ๋ฅผ ํƒœ๊ทธ ๊ฐ’์œผ๋กœ ์•Œ๋ ค์ฃผ๋Š” ํด๋ž˜์Šค์ด๋‹ค. ๋‹ค์Œ์€ ์›๊ณผ ์‚ฌ๊ฐํ˜•์„ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค.

// Tagged class - vastly inferior to a class hierarchy! (Page 109)
public class Figure {
    enum Shape { RECTANGLE, CIRCLE };

    // Tag field - the shape of this figure
    final Shape shape;

    // These fields are used only if shape is RECTANGLE
    double length;
    double width;

    // This field is used only if shape is CIRCLE
    double radius;

    // Constructor for circle
    Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    // Constructor for rectangle
    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);
        }
    }
}

ํƒœ๊ทธ ๋‹ฌ๋ฆฐ ํด๋ž˜์Šค์˜ ํ•ต์‹ฌ์ ์ธ ๋ฌธ์ œ์ ์€ ์‘์ง‘๋„๊ฐ€ ๋‚ฎ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Figure ํด๋ž˜์Šค๋Š” ์›๊ณผ ์‚ฌ๊ฐํ˜•์ด ๋™์‹œ์— ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์›์ผ ๋•Œ ํ•„์š”ํ•œ ํ•„๋“œ์™€ ๋ฉ”์†Œ๋“œ, ์‚ฌ๊ฐํ˜•์ผ ๋•Œ ํ•„์š”ํ•œ ํ•„๋“œ์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ๋‘˜๋‹ค ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ํƒœ๊ทธ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ ํ•„๋“œ๊ฐ€ ํด๋ž˜์Šค ๋ฉค๋ฒ„๋กœ ํฌํ•จ๋œ๋‹ค๋Š” ๊ฒƒ์€ ํด๋ž˜์Šค์˜ ์‘์ง‘๋„๊ฐ€ ๋‚ฎ์•„์งˆ ๊ฒƒ์ž„์„ ์•Œ๋ฆฌ๋Š” ์‹œ๊ทธ๋„์ด๋ฏ€๋กœ ๊ฒฝ๊ณ„ํ•ด์•ผํ•œ๋‹ค.

 

 

์‘์ง‘๋„๊ฐ€ ๋‚ฎ์•„์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ์—ด๊ฑฐํƒ€์ž… ์„ ์–ธ, ํƒœ๊ทธ ํ•„๋“œ, switch ๋ฌธ ๋“ฑ ์“ธ๋ฐ์—†๋Š” ์ฝ”๋“œ๊ฐ€ ๋งŽ๋‹ค.
  • ์—ฌ๋Ÿฌ ๊ตฌํ˜„์ด ํ•œ ํด๋ž˜์Šค์— ํ˜ผํ•ฉ๋˜์–ด์žˆ์–ด ๊ฐ€๋…์„ฑ์ด ๋‚˜์˜๋‹ค.
  • ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ๊ฐ€ ์–ธ์ œ๋‚˜ ํ•จ๊ป˜ ํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋”์‚ฌ์šฉํ•œ๋‹ค.
  • ํ•„๋“œ๋ฅผ final๋กœ ์„ ์–ธํ•˜๋ ค๋ฉด ํ•ด๋‹น ์˜๋ฏธ์— ์“ฐ์ด์ง€ ์•Š๋Š” ํ•„๋“œ๊นŒ์ง€ ์ƒ์„ฑ์ž์—์„œ ์ดˆ๊ธฐํ™”ํ•ด์•ผํ•œ๋‹ค. ์—‰๋šฑํ•œ ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด๋„ ๋Ÿฐํƒ€์ž„์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • ๋˜๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ•œ๋‹ค. switch๋ฌธ์—์„œ ํ•˜๋‚˜๋ผ๋„ ๋น ๋œจ๋ฆฌ๋ฉด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค.

 

์‘์ง‘๋„๋ฅผ ๋†’์ด๋Š” ๋ฐฉ๋ฒ•

 

ํด๋ž˜์Šค์— ํƒœ๊ทธ๊ฐ€ ๋“ค์–ด๊ฐ„ ์ด์œ ๋Š” ๋™์ผํ•œ ํƒ€์ž…(Figure)์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ๋„ ๋‹ค์–‘ํ•œ ์˜๋ฏธ์˜ ๊ฐ์ฒด(Circle, Rectangle ๋“ฑ)์„ ๋งŒ๋“ค๊ณ  ์‹ถ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋‹คํ–‰ํžˆ ์ž๋ฐ”์™€ ๊ฐ™์€ ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด๋Š” ํƒ€์ž… ํ•˜๋‚˜๋กœ ๋‹ค์–‘ํ•œ ์˜๋ฏธ์˜ ๊ฐ์ฒด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ˆ˜๋‹จ์„ ์ œ๊ณตํ•œ๋‹ค. ๋ฐ”๋กœ ํด๋ž˜์Šค ๊ณ„์ธต๊ตฌ์กฐ๋ฅผ ํ™œ์šฉํ•˜๋Š” ์„œ๋ธŒํƒ€์ดํ•‘์ด๋‹ค.

 

ํƒ€์ž… ๊ณ„์ธต

13 ์„œ๋ธŒํด๋ž˜์‹ฑ๊ณผ ์„œ๋ธŒํƒ€์ดํ•‘ (์˜ค๋ธŒ์ ํŠธ์—์„œ ๋ดค๋˜ ๋‚ด์šฉ์ด๋‹ค)

 

13 ์„œ๋ธŒํด๋ž˜์‹ฑ๊ณผ ์„œ๋ธŒํƒ€์ดํ•‘

๋“ค์–ด๊ฐ€๋ฉฐ ํ”ํžˆ ๊ฐ์ฒด์ง€ํ–ฅ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ๋Š” ์ƒ์†์˜ ์šฉ๋„๋ฅผ ๋‘๊ฐ€์ง€๋กœ ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ๋‹ค. 1. ํƒ€์ž… ๊ณ„์ธต์„ ๊ตฌํ˜„ (๋ถ€๋ชจํด๋ž˜์Šค๋Š” ์ž์‹ํด๋ž˜์Šค์˜ ์ผ๋ฐ˜ํ™”์ด๊ณ  ์ž์‹ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจํด๋ž˜์Šค์˜ ํŠน์ˆ˜ํ™”๋‹ค.) 2. ์ฝ”๋“œ

hwannny.tistory.com

ํƒ€์ž… ๊ณ„์ธต์€ ํด๋ž˜์Šค๋“ค์˜ ๊ณ„์ธต์ ์ธ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ํƒ€์ž… ๊ณ„์ธต์€ A is-a B ๊ด€๊ณ„๋ฅผ ํ†ตํ•ด ํ‘œํ˜„๋œ๋‹ค. ์Šˆํผ ํƒ€์ž…์„ A, ์„œ๋ธŒ ํƒ€์ž…์„ B๋กœ ์ •์˜ํ•˜๊ณ  ์ด ๋‘˜์˜ ํƒ€์ž…์ด ๊ด€๊ณ„๋ฅผ ๋งบ๋„๋ก ํ•˜๋Š” ์ž‘์—…์ด ์„œ๋ธŒ ํƒ€์ดํ•‘์ด๋‹ค.

 

is-a ๊ด€๊ณ„๋ฅผ ํŒ๋‹จํ•  ๋•Œ, ๋‹จ์ˆœํžˆ ์–ดํœ˜์ ์œผ๋กœ ๋ชจ๋ธ๋งํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ƒˆ์™€ ํŽญ๊ท„์€ is-a ๊ด€๊ณ„๋ฅผ ๋งŒ์กฑํ•  ์ˆ˜ ์—†๋‹ค. ํŽญ๊ท„์€ ์ƒˆ๋‹ค. ์ƒˆ๋Š” ๋‚  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ํŽญ๊ท„์€ ๋‚  ์ˆ˜ ์—†๋‹ค.

 

is-a ๊ด€๊ณ„๋ฅผ ํŒ๋‹จํ•  ๋•Œ๋Š” ํ–‰๋™ ํ˜ธํ™˜์„ฑ๊ณผ ๋Œ€์ฒด ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•ด์•ผํ•œ๋‹ค. ์„œ๋ธŒํƒ€์ž…์ด ์Šˆํผํƒ€์ž…์ด ํ•˜๋Š” ๋ชจ๋“  ํ–‰๋™์„ ๋™์ผํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ณ , ์Šˆํผํƒ€์ž…์„ ์–ด๋Š ์„œ๋ธŒํƒ€์ž…์œผ๋กœ ๋Œ€์ฒดํ•˜๋”๋ผ๋„ ์‹œ์Šคํ…œ์ด ๋ฌธ์ œ์—†์ด ๋™์ž‘ํ•  ๊ฒƒ์ž„์„ ๋ณด์žฅํ•ด์•ผํ•œ๋‹ค. (๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™์— ์ƒ์„ธํžˆ ๋‚˜์™€์žˆ๋‹ค, ๊ตฌํ˜„๋ฌธ์— ์˜ˆ์™ธ ๋ฑ‰๋Š” ๊ฒƒ์€ ๋Œ€์ฒดํ•  ์ˆ˜ ์—†์Œ์„ ๋œปํ•จ)

 

์œ„์˜ ์˜ˆ์‹œ์—์„œ ํŽญ๊ท„์€ ๋‚  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ์ƒˆ์™€ ํŽญ๊ท„์€ ์„œ๋ธŒ ํƒ€์ž…์ด ๋  ์ˆ˜ ์—†๋‹ค. ์„œ๋ธŒ ํƒ€์ž…์ด ๋˜๋ ค๋ฉด ๋‚˜๋Š” ํ–‰๋™์„ ์ƒˆ๊ฐ€ ์•„๋‹Œ ํŽญ๊ท„๊ณผ ๊ฐ™์€ ์„œ๋ธŒํƒ€์ž…์œผ๋กœ ์˜ฎ๊ฒจ์•ผํ•œ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ƒˆ์™€ ํŽญ๊ท„์€ ์„œ๋ธŒํƒ€์ž…์ด ๋œ๋‹ค.

 

ํ˜น์€ ๋‚˜๋Š” ํ–‰๋™์„ ํ˜‘๋ ฅ์œผ๋กœ ๊ฐ„์ฃผ, ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌํ˜„ํ•˜์—ฌ ์ƒˆ์˜ ํ•˜์œ„ ํƒ€์ž…์ด ์„ ํƒ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•˜๋ฉด ์ƒˆ์™€ ํŽญ๊ท„์€ ์„œ๋ธŒ ํƒ€์ž…์˜ ๊ด€๊ณ„๊ฐ€ ์•„๋‹ˆ๋‹ค. (๋น„๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๋Š” ISP)

 

 

์„œ๋ธŒ ํƒ€์ดํ•‘์˜ ๊ตฌํ˜„

 

์„œ๋ธŒ ํƒ€์ดํ•‘์€ ์ƒ์†์œผ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค. ์Šˆํผ ํƒ€์ž…์€ ๋ถ€๋ชจ ํด๋ž˜์Šค, ์„œ๋ธŒ ํƒ€์ž…์€ ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๋œ๋‹ค.

 

๋ถ€๋ชจ ํด๋ž˜์Šค

  • ๋ชจ๋“  ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ณตํ†ต ํ•„๋“œ
  • ๋™์ผํ•œ ๊ตฌํ˜„์„ ๊ณต์œ ํ•˜๋Š” ์ผ๋ฐ˜ ๋ฉ”์†Œ๋“œ
  • ๋‹คํ˜•์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ์ถ”์ƒ ๋ฉ”์†Œ๋“œ

 

์ž์‹ ํด๋ž˜์Šค

  • ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„
  • ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ํ•„๋“œ

 

Figure์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค์—๋Š” ๋‹คํ˜•์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š”(switch๋ฌธ์„ ๊ตฌํ˜„๋๋˜) area ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๊ฐ€ ๋‚จ๋Š”๋‹ค. ๋‚˜๋จธ์ง€ ํ•„๋“œ์™€ area ๊ตฌํ˜„์€ Figure์„ ์ƒ์†๋ฐ›์€ Rectangle๊ณผ Circle์—์„œ ๊ตฌํ˜„ํ•œ๋‹ค.

public abstract class Figure {
    abstract double area();
}

public class Circle extends Figure {
    final double radius;

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

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

public class Rectangle extends Figure {

    final double length;
    final double width;

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

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

}

 

๋ฆฌํŒฉํ„ฐ๋ง ์ „ํ›„์˜ ์‘์ง‘๋„๋ฅผ ๋น„๊ตํ•ด๋ณด์ž. ํƒœ๊ทธ ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๋Š” Figure์€ ์›๊ณผ ์‚ฌ๊ฐํ˜•์ด ๋™์‹œ์— ๋˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ๊ตฌํ˜„์„ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๊ณ , ํ–‰๋™ ์•ˆ์—์„œ๋„ ๋ถˆํ•„์š”ํ•œ switch๋ฌธ์ด ์žˆ์—ˆ๋‹ค. ๊ฐ€๋…์„ฑ์ด ๋ณ„๋กœ๊ณ  ํƒ€์ž…์ด ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ๊ตฌํ˜„์ด ๋ฐ”๋€Œ์–ด์•ผํ–ˆ๋‹ค. ํ•„๋“œ์˜ ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์„œ๋ธŒ ํƒ€์ดํ•‘ํ•ด์„œ ๋งŒ๋“  Rectangle๊ณผ Circle์€ ๊ฐ์ž์˜ ํ–‰๋™๊ณผ ์ฑ…์ž„์—๋งŒ ์ง‘์ค‘ํ•˜๋ฏ€๋กœ ์‘์ง‘๋„๊ฐ€ ๋†’๋‹ค. ์„œ๋ธŒ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ๋˜ ์ด์œ ๋Š” Rectangle๊ณผ Circle์ด ๋™์ผํ•œ ํ–‰๋™์„ ๊ฐ€์ง€๋ฉฐ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ์Šˆํผ ํƒ€์ž…์„ ๋„์ถœํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์‚ฌ๊ฐํ˜•์˜ ํ•˜์œ„ ํƒ€์ž…์ธ ์ •์‚ฌ๊ฐํ˜•์„ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด Rectangle์„ ์ƒ์†ํ•œ๋‹ค. ์ด๋•Œ ์ •์‚ฌ๊ฐํ˜•์ด ์‚ฌ๊ฐํ˜•์˜ ํ•˜์œ„ ํƒ€์ž…์ด๋ผ๋Š” ๊ฒƒ์€ ์‚ฌ๊ฐํ˜•๊ณผ ๋™์ผํ•œ ํ–‰๋™์ธ area๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ  Rectangle์ด ์‚ฌ์šฉ๋˜๋Š” ๊ณณ์— Square์„ ์‚ฌ์šฉํ•ด๋„ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

public class Square extends Rectangle {
    public Square(double side) {
        super(side, side);
    }
}

 

 

๋ฒˆ์™ธ : ์„œ๋ธŒ ํด๋ž˜์‹ฑ

์„œ๋ธŒ ํด๋ž˜์‹ฑ์ด๋ž€ ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ๋ชฉ์ ์œผ๋กœ ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค. ์„œ๋ธŒ ํด๋ž˜์‹ฑ์€ ๊ตฌํ˜„์ด ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜๋ฏ€๋กœ, ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ๋ชฉ์ ์œผ๋กœ ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ํ•ฉ์„ฑ์ด ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ƒ์†์€ ์„œ๋ธŒ ํƒ€์ดํ•‘์— ์ ์ ˆํ•˜๋‹ค.