๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ“š์ฝ์€ ์ฑ… ์ •๋ฆฌ/์ž๋ฐ” ์ฝ”๋”ฉ์˜ ๊ธฐ์ˆ 

[์ž๋ฐ” ์ฝ”๋”ฉ์˜ ๊ธฐ์ˆ ] 7์žฅ : ๊ฐ์ฒด ๋””์ž์ธ

์ž๋ฐ”์˜ ํด๋ž˜์Šค์™€ ๊ฐ์ฒด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ธฐ๋Šฅ๋งŒ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์€ ๋ถ€์กฑํ•˜๋‹ค!

๋ณด๊ธฐ ์ข‹์•„์•ผ ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํŽธํ•ด์•ผ๋งŒ ํ•œ๋‹ค!!

7์žฅ์—์„œ๋Š” ๋” ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ด๊ณ  ๊ฐ•๋ ฅํ•œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ผ ์ž๋ฐ”์˜ ๋ณดํŽธ์ ์ธ ๋””์ž์ธ ์›๋ฆฌ๋ฅผ ๊ฐ•์กฐํ•˜๊ฒ ๋‹ค.

 

7.1 ๋ถˆ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฉ”์„œ๋“œ ๋ถ„ํ• 

๋ฌธ์ œ ์ฝ”๋“œ

    void log(String message, boolean classified) throws IOException {
        if (classified) {
            writeMessage(message, CAPTAIN_LOG);
        } else {
            writeMessage(message, CREW_LOG);
        }
    }

์œ„ ์ฝ”๋“œ๋Š” boolean์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ์„œ๋กœ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์ด๋Š” ๋™์ž‘์— ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ์ฝ๊ธฐ ๋ถˆํŽธํ•˜๊ณ  ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์ด True์™€ False๊ฐ€ ๊ฐ๊ฐ ๋ฌด์Šจ ์˜๋ฏธ์ธ์ง€ ์•Œ๊ณ  ์žˆ์–ด์•ผ๋งŒ ํ•œ๋‹ค.

 

์ด ์ฝ”๋“œ๋ฅผ ์ข€ ๋” ํ–ฅ์ƒ ์‹œํ‚ค๋ ค๋ฉด boolean ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์‹ค์ œ๋กœ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. (ํ˜ผ๋™์„ ์ค„์ž„)

๊ฐœ์„  ์ฝ”๋“œ

    void writeToCaptainLog(String message) throws IOException {
        writeMessage(message, CAPTAIN_LOG);
    }

    void writeToCrewLog(String message) throws IOException {
        writeMessage(message, CREW_LOG);
    }

์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ boolean์ด ์“ฐ์ธ ๋ฉ”์„œ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ ์ฝ”๋“œ๊ฐ€ ํ–ฅ์ƒ๋  ์ˆ˜ ์žˆ๋‹ค.

 

*๊ฐœ์„  ๋ฐฉ๋ฒ•*

1. ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๊ตฌ๋ถ„ํ•˜๋˜ ์ œ์–ด ํ๋ฆ„ ๊ฒฝ๋กœ๋งˆ๋‹ค ์ƒˆ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€

2. ๋ฉ”์„œ๋“œ์— ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„์„ ์ง€์–ด์ฃผ์–ด ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ๋†’์ž„

๋ฉ”์„œ๋“œ๊ฐ€ ์–ด๋””์— ์†ํ•˜๋ฉฐ ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ๋ฉ”์„œ๋“œ๋ช…๋งŒ ๋ด๋„ ํ™•์‹คํžˆ ์•Œ ์ˆ˜ ์žˆ์–ด์ง.

7.2 ์˜ต์…˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฉ”์„œ๋“œ ๋ถ„ํ• 

์˜ต์…˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ๋ถˆ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ฒ˜๋Ÿผ ๋ฉ”์„œ๋“œ ๋ถ„ํ• ์„ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฌธ์ œ ์ฝ”๋“œ

class Logbook {

    static final Path CREW_LOG = Paths.get("/var/log/crew.log");

    List<String> readEntries(LocalDate date) throws IOException {
        final List<String> entries = Files.readAllLines(CREW_LOG,
                StandardCharsets.UTF_8);
        if (date == null) {
            return entries;
        }

        List<String> result = new LinkedList<>();
        for (String entry : entries) {
            if (entry.startsWith(date.toString())) {
                result.add(entry);
            }
        }
        return result;
    }
}

 

์ธ์ž๋กœ null ์ธ ๊ฒƒ๊ณผ null์ด ์•„๋‹Œ ๊ฒƒ์ด ๋„˜์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋•Œ ์„œ๋กœ ๋‹ค๋ฅธ ์ž‘์—…์ด ์‹คํ–‰๋œ๋‹ค.

ํ˜ธ์ถœ์ž ์ž…์žฅ์—์„œ null๋กœ ์ธ์ž๋กœ ๋„˜๊ธธ ๋•Œ ์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ์ง€ ์˜ˆ์ƒํ•˜๊ธฐ ์–ด๋ ต๋‹ค..

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ถ€๋ถ„์„ ๋ฆฌํŒฉํ† ๋ง ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐœ์„  ์ฝ”๋“œ

class Logbook {

    static final Path CREW_LOG = Paths.get("/var/log/crew.log");

    List<String> readEntries(LocalDate date) throws IOException {
        Objects.requireNonNull(date);
        
        List<String> result = new LinkedList<>();
        for (String entry : readAllEntries()) {
            if (entry.startsWith(date.toString())) {
                result.add(entry);
            }
        }
        return result;
    }

    List<String> readAllEntries() throws IOException {
        return Files.readAllLines(CREW_LOG, StandardCharsets.UTF_8);
    }
}

'๋ถˆ ๋งค๊ฐœ๋ณ€์ˆ˜'๋ฅผ ๊ฐœ์„ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ '์˜ต์…˜ ๋งค๊ฐœ๋ณ€์ˆ˜' ๋˜ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋ถ„ํ• ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

*๊ฐœ์„  ๋ฐฉ๋ฒ•*

1. ๊ฐ๊ฐ์˜ ์ œ์–ด ํ๋ฆ„์„ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋กœ ํ‘œํ˜„.

2. ๋ฉ”์„œ๋“œ๋ช…์„ ํ†ตํ•ด ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ์ง€ ๋ช…ํ™•ํžˆ ์ „๋‹ฌ.

 

readAllEntriles()๋Š” '๋ชจ๋“  ์—”ํŠธ๋ฆฌ๋ฅผ ์ฝ์–ด์˜จ๋‹ค'๋ผ๋Š” ์˜๋ฏธ๋ฅผ ํ•œ๋ˆˆ์— ์•Œ ์ˆ˜ ์žˆ๊ณ  ๋” ์ด์ƒ null์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

7.3 ๊ตฌ์ฒด ํƒ€์ž…๋ณด๋‹ค ์ถ”์ƒ ํƒ€์ž…

๋ณ€์ˆ˜์— ์ถ”์ƒ์ ์ธ ํƒ€์ž…์„ ์‚ฌ์šฉํ• ์ˆ˜๋ก ์ฝ”๋“œ๋Š” ๋” ์œ ์—ฐํ•ด์ง„๋‹ค!

๋ฌธ์ œ ์ฝ”๋“œ

class Inventory {
    LinkedList<Supply> supplies = new LinkedList();

    void stockUp(ArrayList<Supply> delivery) {
        supplies.addAll(delivery);
    }

    LinkedList<Supply> getContaminatedSupplies() {
        LinkedList<Supply> contaminatedSupplies = new LinkedList<>();
        for (Supply supply : supplies) {
            if (supply.isContaminated()) {
                contaminatedSupplies.add(supply);
            }
        }
        return contaminatedSupplies;
    }
}

class Usage {
    static void main(String[] args) {
        CargoShip cargoShip = null;
        Inventory inventory = null;
        Stack<Supply> delivery = cargoShip.unload();
        ArrayList<Supply> loadableDelivery = new ArrayList<>(delivery);
        inventory.stockUp(loadableDelivery);
    }
}

์œ„ ์ฝ”๋“œ๋Š” LinkenList<>, ArraryList<> ๋“ฑ์˜ ๊ตฌ์ฒด ํƒ€์ž…์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด๋‚˜, ๋ณ€์ˆ˜ ํƒ€์ž…์„ ์ง€์ •ํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์—ฌ๋Ÿฌ ์ž๋ฃŒ ๊ตฌ์กฐ ๊ฐ„ ํƒ€์ž… ๊ฐ„ ๋ณ€ํ™˜์ด ์žฆ์•„์ง€๊ณ  Inventoryํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ถ€๋ถ„์—๋„ ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฒŒ ๋œ๋‹ค....(๊ฐ์ฒด ์ง€ํ–ฅ์— ์•ˆ์ข‹์Œ)

 

์ถ”์ƒ ํƒ€์ž…์„ ์“ฐ๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐœ์„  ์ฝ”๋“œ

class Inventory {
    List<Supply> supplies = new LinkedList();

    void stockUp(Collection<Supply> delivery) {
        supplies.addAll(delivery);
    }

    List<Supply> getContaminatedSupplies() {
        List<Supply> contaminatedSupplies = new LinkedList<>();
        for (Supply supply : supplies) {
            if (supply.isContaminated()) {
                contaminatedSupplies.add(supply);
            }
        }
        return contaminatedSupplies;
    }
}

์ฝ”๋“œ๊ฐ€ ๊ฐœ์„  ๋œ 3๊ฐ€์ง€ ์ธก๋ฉด์„ ์‚ดํŽด๋ณด์ž.

  1. supplies ํ•„๋“œ์— List ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ -> ์ธ๋ฒคํ† ๋ฆฌ์— ์ œํ’ˆ์ด ์–ด๋–ป๊ฒŒ ์ €์žฅ๋˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์–ด์ง (๋‹ค์–‘ํ•œ ๊ฐ์ฒด ๋„ฃ์„ ์ˆ˜ ์žˆ์–ด์ง)
  2. stockUp() ๋ฉ”์„œ๋“œ๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์–ด๋–ค Collection์ด๋“  ํ—ˆ์šฉ -> ์ฆ‰, ์–ด๋–ค ํ•˜์œ„ ํƒ€์ž…์ด๋“  ๋ฉ”์„œ๋“œ๋กœ ์ „๋‹ฌ ๊ฐ€๋Šฅํ•ด์ง.
  3. getConataminatedSupplies() ๊ตฌ์ฒด์ ์ธ ํƒ€์ž…์ด ์•„๋‹Œ ์ถ”์ƒ์ ์ธ List<> ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•จ.
    -> ์ œํ’ˆ์˜ ๋ฐ˜ํ™˜์€ Listํ˜•ํƒœ์ด์ง€๋งŒ ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์ €์žฅํ–ˆ๋Š” ์ง€๋Š” ์™ธ๋ถ€์— ์•Œ๋ฆฌ์ง€ ์•Š์Œ
class Usage {
    static void main(String[] args) {
        CargoShip cargoShip = null;
        Inventory inventory = null;
        Stack<Supply> delivery = cargoShip.unload();
        inventory.stockUp(delivery);
    }
}

stockUp ์‚ฌ์šฉ ์‹œ ํƒ€์ž… ๋ณ€ํ™˜ ์—†์ด Stack ํƒ€์ž…์„ ๋ฐ”๋กœ Collection์œผ๋กœ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

7.4 ๊ฐ€๋ณ€ ์ƒํƒœ๋ณด๋‹ค ๋ถˆ๋ณ€ ์ƒํƒœ ์‚ฌ์šฉํ•˜๊ธฐ

๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ์ฒด์˜ ์ƒํƒœ๋Š” ๋ถˆ๋ณ€์ด๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด ๊ฐ์ฒด๋ฅผ ๋ถˆ๋ณ€์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ ์ž˜๋ชป ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ๊ฐ€ ์ ๋‹ค.

๋ฌธ์ œ ์ฝ”๋“œ

class Distance {
    DistanceUnit unit;
    double value;

    Distance(DistanceUnit unit, double value) {
        this.unit = unit;
        this.value = value;
    }

    static Distance km(double value) {
        return new Distance(DistanceUnit.KILOMETERS, value);
    }

    void add(Distance distance) {
        distance.convertTo(unit);
        value += distance.value;
    }

    void convertTo(DistanceUnit otherUnit) {
        double conversionRate = unit.getConversionRate(otherUnit);
        unit = otherUnit;
        value = conversionRate * value;
    }
}


class Main {
    static void usage() {
        Distance toMars = new Distance(DistanceUnit.KILOMETERS, 56_000_000);
        Distance marsToVenus = new Distance(DistanceUnit.LIGHTYEARS, 0.000012656528);
        Distance toVenusViaMars = toMars;
        toVenusViaMars.add(marsToVenus);
    }
}

toMars์™€ toVenusViaMars๋Š” ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค. ๋”ฐ๋ผ์„œ, toVenusViaMars.add(marsToVenus)๋ฅผ ์‹คํ–‰ํ•˜๋ฉด toMars๊ฐ์ฒด๋„ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜๊ฒŒ ๋œ๋‹ค. (value ๊ฐ’์€ ๋ณ€๋™)

๊ฐœ์„  ์ฝ”๋“œ

final class Distance {
    final DistanceUnit unit;
    final double value;


    Distance(DistanceUnit unit, double value) {
        this.unit = unit;
        this.value = value;
    }

    Distance add(Distance distance) {
        return new Distance(unit, value + distance.convertTo(unit).value);
    }

    Distance convertTo(DistanceUnit otherUnit) {
        double conversionRate = unit.getConversionRate(otherUnit);
        return new Distance(otherUnit, conversionRate * value);
    }
}

class Main {
    static void usage() {
        Distance toMars = new Distance(DistanceUnit.KILOMETERS, 56_000_000);
        Distance marsToVenus = new Distance(DistanceUnit.LIGHTYEARS, 0.000012656528);
        Distance toVenusViaMars = toMars.add(marsToVenus)
                                        .convertTo(DistanceUnit.MILES);
    }
}

๊ฐ์ฒด๋Š” ์œ ํšจํ•˜์ง€ ์•Š์€ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋„๋ก ๊ฐ€๋ณ€์„ฑ์„ ์ œํ•œํ•ด ์Šค์Šค๋กœ๋ฅผ ๋ณดํ˜ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ƒ์„ฑ์ž์˜ value์™€ unitํ•„๋“œ์— final ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ดํ›„๋กœ๋Š” ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.

๋”ฐ๋ผ์„œ, ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜๋ ค๋ฉด ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

add() ์™€ convertTo() ํ•จ์ˆ˜๋Š” ์ˆ˜ํ–‰ ํ›„ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Distance์˜ ๋ถˆ๋ณ€ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํด๋ž˜์Šค ์ •์˜ ์•ž์— final ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋Š” ๊ฒฝ์šฐ๋Š” ํด๋ž˜์Šค๋ฅผ ๋” ์ด์ƒ ํ™•์žฅํ•  ์ˆ˜ ์—†๊ฒŒ ํ•˜๋ ค๋Š” ์˜๋„์ด๋‹ค.

7.5 ์ƒํƒœ์™€ ๋™์ž‘ ๊ฒฐํ•ฉํ•˜๊ธฐ

๋ฌธ์ œ ์ฝ”๋“œ

class Hull {
    int holes;
}


class HullRepairUnit {

    void repairHole(Hull hull) {
        if (isIntact(hull)) {
            return;
        }
        hull.holes--;
    }

    boolean isIntact(Hull hull) {
        return hull.holes == 0;
    }
}

์ƒํƒœ์™€ ๋™์ž‘์˜ ๊ฒฐํ•ฉ์€ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋ก๊ทธ๋ž˜๋ฐ์˜ ๊ธฐ๋ณธ ํ‹€ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

์œ„ ์ฝ”๋“œ๋Š” ์ƒํƒœ์™€ ๋™์ž‘์ด ๋ณ„๊ฐœ์˜ ํด๋ž˜์Šค๋กœ ๋‚˜๋‰˜์–ด ์žˆ๋‹ค.

 

์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ๋Š” '์ •๋ณด ์€๋‹‰'์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์ง€๊ณ  ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ๋” ์–ด๋ ค์›Œ์ง„๋‹ค๋Š” ์ ์ด๋‹ค.

Hull ํด๋ž˜์Šค๋Š” HullRepairUnit ๋ฐ”๊ฐ™์— ์žˆ๋Š” ํด๋ž˜์Šค์ด๋ฏ€๋กœ ์ž์‹ ์˜ ์ƒํƒœ์— ๋Œ€ํ•ด ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ์ œ๊ณตํ•ด์•ผ๋งŒ ํ•œ๋‹ค.

 

์ƒํƒœ์™€ ๋™์ž‘์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฒฐํ•ฉํ•ด์„œ ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•ด๋ณด์ž.

๊ฐœ์„  ์ฝ”๋“œ

class Hull {
    int holes;

    void repairHole() {
        if (isIntact()) {
            return;
        }
        holes--;
    }

    boolean isIntact() {
        return holes == 0;
    }
}

HullRepairUnit์„ ์™„์ „ํžˆ ์ง€์› ๋‹ค. ์ด์ œ Hull์€ ์Šค์Šค๋กœ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

Hull ๋ฉ”์„œ๋“œ๋Š” ์ž์‹ ์˜ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ง์ ‘ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ  ๋ฉ”์„œ๋“œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋˜ํ•œ, ๊ฒŒํ„ฐ, ์„ธํ„ฐ๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€๋กœ ์ƒํƒœ๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

 

์š”์•ฝํ•˜๋ฉด ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์ž…๋ ฅ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ๋‹ค๋ฃจ๊ณ  ์ž์‹ ์ด ์†ํ•œ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ์œ ์‹ฌํžˆ ๋ด์•ผํ•œ๋‹ค.

์ด๊ฒƒ์€ ์ƒํƒœ์™€ ๋™์ž‘์ด ๋ถ„๋ฆฌ๋˜์—ˆ๋‹ค๋Š” ์˜๋ฏธ์ด๊ณ  ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋กœ๋Š” '์ •๋ณด ์€๋‹‰'์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

7.6 ์ฐธ์กฐ ๋ˆ„์ˆ˜ ํ”ผํ•˜๊ธฐ

๋ฌธ์ œ ์ฝ”๋“œ

class Inventory {

    private final List<Supply> supplies;

    Inventory(List<Supply> supplies) {
        this.supplies = supplies;
    }

    List<Supply> getSupplies() {
        return supplies;
    }
}

class Usage {

    static void main(String[] args) {
        List<Supply> externalSupplies = new ArrayList<>();
        Inventory inventory = new Inventory(externalSupplies);

        inventory.getSupplies().size(); // == 0
        externalSupplies.add(new Supply("Apple"));
        inventory.getSupplies().size(); // == 1

        inventory.getSupplies().add(new Supply("Banana"));
        inventory.getSupplies().size(); // == 2
    }
}

์œ„ ์ฝ”๋“œ๋Š” ์–ด๋А ๋ถ€๋ถ„์ด ๋ฌธ์ œ๊ฐ€ ๋ ๊นŒ?

 

๋จผ์ € inventory๋Š” ๋‚ด๋ถ€์˜ ์ œํ’ˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „ํ˜€ ๋ณดํ˜ธํ•˜์ง€ ์•Š๋Š”๋‹ค!

 

์œ„ ์ฝ”๋“œ์—์„œ ์žฌ๊ณ  ์ถ”๊ฐ€๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ๊ฐ€๋Šฅํ•˜๋‹ค....

1. ์™ธ๋ถ€์—์„œ ์ƒ์„ฑํ•œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ด์šฉํ•ด ์žฌ๊ณ  ์ถ”๊ฐ€ -> externalSupplies.add(new Supply("Apple")); 

2. ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ ์ฐธ์กฐํ•ด ์™ธ๋ถ€์—์„œ ์žฌ๊ณ  ์ถ”๊ฐ€ -> inventory.getSupplies().add(new Supply("Banana"));

 

๊ทธ๋ ‡๋‹ค๋ฉด ํด๋ž˜์Šค ๋‚ด๋ถ€๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ ํ›„ ์กฐ์ž‘๋˜์ง€ ์•Š๋„๋ก ๋ณดํ˜ธํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ??

class Inventory {

    private final List<Supply> supplies;

    Inventory(List<Supply> supplies) {
        this.supplies = new ArrayList<>(supplies);
    }

    List<Supply> getSupplies() {
        return Collections.unmodifiableList(supplies);
    }
}

class Usage {

    static void main(String[] args) {
        List<Supply> externalSupplies = new ArrayList<>();
        Inventory inventory = new Inventory(externalSupplies);

        inventory.getSupplies().size(); // == 0
        externalSupplies.add(new Supply("Apple"));
        inventory.getSupplies().size(); // == 0

        // UnsupportedOperationException
        inventory.getSupplies().add(new Supply("Banana"));
    }
}

๋จผ์ € ์œ„ ์ฝ”๋“œ๋Š” ์ „๋‹ฌํ•œ ๋ฆฌ์ŠคํŠธ์˜ ์ฐธ์กฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฆฌ์ŠคํŠธ ๋‚ด Supply๊ฐ์ฒด๋กœ ๋‚ด๋ถ€ ArrayList๋ฅผ ์ฑ„์šด๋‹ค.

-> this.supplies = new ArrayList<>(supplies); (๋ฐฉ์–ด ๋ณต์‚ฌ)

 

๊ทธ๋ฆฌ๊ณ  getSupplies() ํ˜ธ์ถœ ์‹œ -> return Collections.unmodifiableList(supplies); ๋กœ ๋ž˜ํ•‘ํ•œ ํ›„ ๋ฐ˜ํ™˜ํ•ด์„œ ์ฝ๊ธฐ ์ ‘๊ทผ๋งŒ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์™ธ๋ถ€์—์„œ๋Š” ๋‚ด๋ถ€์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์—†์œผ๋‹ˆ ์™ธ๋ถ€์—์„œ ๋‚ด๋ถ€๋กœ ์˜ํ–ฅ์„ ์ฃผ์ง€ ๋ชปํ•œ๋‹ค.

7.7 ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ธฐ

๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ๋ฐ˜ํ™˜ํ•  ๊ฐ’์ด ์—†์œผ๋ฉด ๊ทธ๋ƒฅ 'null'์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์žˆ๋‹ค. ์ด๊ฒƒ์€ ํ”„๋กœ๊ทธ๋žจ์˜ ์•ˆ์ •์„ฑ์„ ํ•ด์น˜๋Š” ํ–‰๋™์ด๋‹ค.

๋ฌธ์ œ ์ฝ”๋“œ

class SpaceNations {

    static List<SpaceNation> nations = Arrays.asList(
            new SpaceNation("US", "United States"),
            new SpaceNation("RU", "Russia")
    );

    static SpaceNation getByCode(String code) {
        for (SpaceNation nation : nations) {
            if (nation.getCode().equals(code)) {
                return nation;
            }
        }
        return null;
    }
}

์œ„ ์ฝ”๋“œ๋Š” getByCode() ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ ์‹œ code๊ฐ€ ๊ฐ™์€ ๊ฒƒ์ด ์—†๋‹ค๋ฉด 'null'์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

์ด๋Š” ๊ฐ™์€ ๊ตญ๊ฐ€ ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค๋ฉด ๋„ˆ๋ฌด ์‰ฝ๊ฒŒ 'NullPointerException'์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

๋ฌผ๋ก  ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์—์„œ null์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€๋Š” ์žŠ์–ด๋ฒ„๋ฆฌ๊ณ  ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒํ•˜๊ฒŒ ๋‘˜ ์ˆ˜ ์žˆ๋‹ค..

 

๋”ฐ๋ผ์„œ, null๋ง๊ณ  ๋‹ค๋ฅธ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ชฝ์œผ๋กœ ๊ฐœ์„ ํ•ด๋ณด์ž.

๊ฐœ์„  ์ฝ”๋“œ

class SpaceNations {

    /** Null object. */
    static final SpaceNation UNKNOWN_NATION = new SpaceNation("", "");

    static List<SpaceNation> nations = Arrays.asList(
            new SpaceNation("US", "United States"),
            new SpaceNation("RU", "Russia")
    );

    static SpaceNation getByCode(String code) {
        for (SpaceNation nation : nations) {
            if (nation.getCode().equals(code)) {
                return nation;
            }
        }
        return UNKNOWN_NATION;
    }
}

์œ„ ์ฝ”๋“œ๋Š” "๋„ ๊ฐ์ฒด ํŒจํ„ด"์„ ์‚ฌ์šฉํ–ˆ๋‹ค. null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹  ๋„ ๊ฐ์ฒด(null object), ์ฆ‰ ๊ฐ์ฒด์— ์‹ค์งˆ์ ์ธ ๊ฐ’์ด ์—†์Œ์„ ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. 

 

์˜ˆ์ œ์—์„œ๋Š” UNKOWN_NATION -> SpaceNation("", "")

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ˜ธ์ถœ์ž์ชฝ์—์„œ 'NullPointerException'์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋„ ๊ฐ์ฒด๋ฅผ ๋ฌด์‹œํ• ์ง€ ์˜ˆ์™ธ๋ฅผ ๋˜์งˆ ์ง€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.

7.8 7์žฅ์—์„œ ๋ฐฐ์šด ๋‚ด์šฉ

์šฐ๋ฆฌ๋Š” ์ฝ”๋“œ ์ž‘์„ฑ์ž๊ฐ€ ์–ด๋–ค ๊ทผ๊ฑฐ๋กœ ๋””์ž์ธ ๊ฒฐ์ •์„ ๋‚ด๋ ธ๋Š”์ง€ ์•Œ์•„๋‚ด๋Š”๋ฐ ๋งŽ์€ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์—ฌ์•ผ ํ•œ๋‹ค.

 

์ฝ”๋“œ ๋””์ž์ธ์€ ํ•ญ์ƒ ์„ ํƒ์˜ ์—ฐ์†์ด๋ฉฐ ๊ทธ ๋“์‹ค์— ๋Œ€ํ•œ ์ฑ…์ž„์€ ๊ฐœ๋ฐœ์ž์˜ ๋ชซ์ด๋‹ค.

 

<๊ฐ€๋…์„ฑ>, <ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ>, <์œ ์ง€ ๋ณด์ˆ˜์„ฑ>, <์„ฑ๋Šฅ> ๋“ฑ์˜ ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„๋ฅผ ๊ณ ๋ คํ•ด ๊ฐœ๋ฐœ์ž๋Š” ์˜ฌ๋ฐ”๋ฅธ ๊ฒฐ์ •์„ ๋‚ด๋ ค์•ผ ํ•œ๋‹ค.