JiwonDev

์˜ค๋ธŒ์ ํŠธ ๋””์ž์ธ ์Šคํƒ€์ผ #1 ๊ฐ์ฒด์ง€ํ–ฅ, ์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ

by JiwonDev

์ฑ… ์›๋ฌธ

 

์˜ค๋ธŒ์ ํŠธ ๋””์ž์ธ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ - YES24

์ž˜ ์ž‘์„ฑํ•œ ๊ฐ์ฒด์ง€ํ–ฅ ์ฝ”๋“œ๋Š” ์ฝ๊ณ  ๋ณ€๊ฒฝํ•˜๊ณ  ๋””๋ฒ„๊ทธํ•˜๊ธฐ ์ฆ๊ฒ๋‹ค. ์ด ์ฑ…์—์„œ ๋ณด์—ฌ์ฃผ๋Š” ๊ฐ์ฒด ๋””์ž์ธ์— ๋Œ€ํ•œ ๋ณดํŽธ์  ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ตํ˜€ ์ฝ”๋”ฉ ์Šคํƒ€์ผ์„ ํ–ฅ์ƒํ•˜์ž. ์ด ๋ช…ํ™•ํ•œ ๊ทœ์น™์€ ์–ด๋–ค ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด

www.yes24.com

ํ•ด๋‹น ์ฑ…์„ ๋ฐ”ํƒ•์œผ๋กœ ์ œ ์ƒ๊ฐ์„ ์„ž์–ด์„œ ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฑ…์—๋Š” ์—†๋Š” ๋‚ด์šฉ์ด ์ถ”๊ฐ€๋กœ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜€

 

[ #0. ๊ฐ์ฒด์ง€ํ–ฅ ์šฉ์–ด ]

ํ•ด๋‹น ๊ธ€์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์šฉ์–ด๋“ค์ด ์‚ฌ์šฉ๋œ๋‹ค. ์ƒ์†Œํ•œ ์šฉ์–ด๋“ค์ด ์žˆ๋‹ค๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณด๊ณ  ๋„˜์–ด๊ฐ€์ž.

๋”๋ณด๊ธฐ
  • ํด๋ž˜์Šค(class)์™€ ๊ฐ์ฒด(object)
     โžก ๊ฐ์ฒด๋Š” ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š” ์‚ฌ๋ฌผ, ๊ฐœ๋…์ด๋ฉฐ ํด๋ž˜์Šค๋Š” ๊ทธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋กœ ์ •์˜ ํ•ด ๋†“์€ ๊ฒƒ์ด๋‹ค.

  • ์ƒํƒœ(State) ๋˜๋Š” ์†์„ฑ(property)
     โžก ๊ฐ์ฒด๋Š” ์ƒํƒœ ๊ฐ’(state)๊ณผ ํ–‰์œ„(behavior), ๋‹ค๋ฅธ ๋ง๋กœ ์†์„ฑ(property)๊ณผ ๊ธฐ๋Šฅ(method)์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.
     โžก ์†์„ฑ์— ํฌํ•จ๋˜๋Š” ๊ฒƒ: ํด๋ž˜์Šค ๋ฉค๋ฒ„ ๋ณ€์ˆ˜(member variable), ์ธ์Šคํ„ด์Šค ํ•„๋“œ(filed), ํŠน์„ฑ(attribute), ์ƒํƒœ(state)

  • ๋ณ€๊ฒฝ๊ฐ€๋Šฅ(mutable), ๋ณ€๊ฒฝ๋ถˆ๊ฐ€๋Šฅ(immutable)
     โžก ์™ธ๋ถ€์—์„œ ๋ฉ”์„œ๋“œ ๊ฒฐ๊ณผ๊ฐ’์— ์˜ํ–ฅ(side-effect)์„ ๋ชป๋ผ์น˜๊ฒŒ ๊ฐ์ฒด ์†์„ฑ์„ ๋ถˆ๋ณ€(immutable)ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

  • ํ–‰์œ„(behavior)์™€ ๋ฉ”์„œ๋“œ(method)
     โžก ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง„ ํ–‰์œ„์ด๋‹ค. ๋ฉ”์„œ๋“œ(method), ํ•จ์ˆ˜(function)

  • ์˜์กด์„ฑ(dependency)
     โžก ์ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์˜์กด์„ฑ(dependency)

  • ์ƒ์†(inheritance, extend)
     โžก ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์ƒ์†์ด๋ผ๋Š” ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ๋”ฐ์ง€๊ณ  ๋ณด๋ฉด ๊ฐ์ฒด์˜ ํ™•์žฅ(extends)์ด ์ •ํ™•ํ•œ ์˜๋ฏธ.

  • ๊ตฌ์„ฑ(composition, is - a)
     โžก ํ”ํžˆ ์ƒ์†๊ณผ ๋น„๊ต๋˜๋Š” ๋ง๋กœ์„œ, ๊ฐ์ฒด๋ฅผ ์ƒ์†ํžˆ์ง€ ์•Š๊ณ  ๋‚ด ์†์„ฑ์— ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ํ• ๋‹นํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. 

  • ๋ฐ˜ํ™˜(return)๊ณผ ์˜ˆ์™ธ(exception)
     โžก ๊ฐ์ฒด์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋• ํŠน์ • ์˜ˆ์™ธ ๊ฐ’์„ ๋ฐ˜ํ™˜(return)ํ•˜๊ฑฐ๋‚˜ ์˜ˆ์™ธ(throw)๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด๋‹ค.

  • ๋‹จ์œ„ํ…Œ์ŠคํŠธ(unit test)
     โžก ๊ฐ์ฒด ๋‹จ์œ„์˜ ์œ ๋‹› ํ…Œ์ŠคํŠธ. ํ•œ๊ธ€๋กœ ๋ฒˆ์—ญํ•ด์„œ ์กฐ๊ธˆ ์–ด์ƒ‰ํ•˜๋‹ค. ํ•„์š”ํ•œ ์˜์กด์„ฑ์€ ํ…Œ์ŠคํŠธ ๋”๋ธ”(test double)๋กœ ๋Œ€์ฒดํ•˜๊ณ  ์ค€๋น„-์‹คํ–‰-ํ™•์ธ (Arragne-Act,Assert ๋˜๋Š” Given-When-Then)์œผ๋กœ ์‹คํŒจ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋‚˜์”ฉ ๋งŒ๋“ ๋‹ค.

  • ํ…Œ์ŠคํŠธ ๋”๋ธ”(test double)
     โžก ์˜ํ™”๋ฐฐ์šฐ์˜ ์Šคํ„ดํŠธ ๋”๋ธ”(stunt double)์—์„œ ๋”ฐ์˜จ ๋ง๋กœ, ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์ž„์‹œ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
     โžก ํ…Œ์ŠคํŠธ ๋”๋ธ” ๊ฐ์ฒด์—๋Š” Dummy(์•„๋ฌด๊ฒƒ๋„ ์•ˆํ•จ), Stub(ํŠน์ • ๊ณ ์ • ๊ฐ’ ๋ฐ˜ํ™˜), Fake(์ผ๋ถ€๋งŒ ๋™์ž‘), Spy(Stub + logging),     Mock(ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋œ ๊ฐ€์งœ ๊ฐ์ฒด, ์ ์–ด๋…ผ ์‹œ๋‚˜๋ฆฌ์˜ค๋Œ€๋กœ ๋™์ž‘)๋“ฑ์ด ์žˆ๋‹ค.

 


[ #1. ๊ฐ์ฒด๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ•˜๊ธฐ ]

๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๊ธฐ๋ณธ์„ ์„ค๋ช…ํ•œ๋‹ค. ์ด๋ฏธ ์ž˜ ์•Œ๊ณ ์žˆ๋‹ค๋ฉด ๋ฐ”๋กœ [ #2 ] ๋กœ ๋„˜์–ด๊ฐ€๋Š”๊ฑธ ์ถ”์ฒœํ•œ๋‹ค.

๐Ÿ“Œ ๊ฐ์ฒด๋Š” ์ฃผ์–ด์ง„ ํด๋ž˜์Šค๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

๊ฐ์ฒด์˜ ์ •์˜. ์ด๋ฅผ ๋‹ค๋ฅธ ๋ง๋กœ ๊ฐ์ฒด์˜ ๋ชจ๋ธ๋ง์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.

ํด๋ž˜์Šค ์ƒ์†, ์ธํ„ฐํŽ˜์ด์Šค, ๋‹คํ˜•์„ฑ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋ชจ๋ธ๋งํ•˜๊ณ  ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

ํ˜„์‹ค ์„ธ๊ณ„์—์„œ ์กด์žฌํ•˜๋Š” ๊ฐ์ฒด์˜ ํ•„์š”ํ•œ ์†์„ฑ, ํ–‰์œ„๋ฅผ ๋ฝ‘์•„์„œ ๋ชจ๋ธ๋งํ•œ๋‹ค.

public class Person {
    private String name;
    private int age;
    
    public void eat() {
        System.out.println("eat");
    }
    public void sleep() {
        System.out.println("sleep");
    }
}
public class Developer extends Person { // ์ƒ์†์„ ์ด์šฉํ•ด ๊ฐ์ฒด๋ฅผ ํ™•์žฅํ•œ๋‹ค.
    public void coding(){
        // Developer ๋Š” eat, sleep ๋ง๊ณ ๋„ coding๊นŒ์ง€ ๊ฐ€๋Šฅํ•˜๋‹ค. 
        System.out.println("coding");
    }
}
 

#1 ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์บก์Šํ™”, ์ถ”์ƒํ™”, ์ƒ์†, ๋‹คํ˜•์„ฑ... ๋งŽ์ด ๋“ค์–ด๋ดค์ง€๋งŒ, ์ •์ž‘ ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€์ง€ ์ž˜ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ํ•ด๋‹น ๊ธ€์—์„œ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ๊ฐœ๋…์ด ์™œ ์ƒ๊ฒผ๊ณ , ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ง€

jiwondev.tistory.com

 

 

๐Ÿ“Œ ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ์˜์กด์„ฑ์€ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ƒ์„ฑ์ž๋กœ ์ฃผ์ž… ๋ฐ›์•„ ์ฆ‰์‹œ ์‚ฌ์šฉํ•œ๋‹ค.

class ContentWriter {
    FileReader reader;  // ํŒŒ์ผ์„ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” FileReader ๊ฐ์ฒด์˜ ์˜์กด์„ฑ์ด ํ•„์š”ํ•˜๋‹ค.

    ContentWriter() {
        this.reader = new FileReader("hello.txt");
        // ์ด๋ ‡๊ฒŒ ๊ฐ์ฒด ์•ˆ์—์„œ ํ•„์š”ํ•œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด๊ธด ํ•˜๋‹ค.
    }

    public void print() {
        String content = reader.readAll();
        System.out.println(content);
    }
}

์ด๋ฅผ ์ƒ์„ฑ์ž ์ฃผ์ž…์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์„œ [๊ฐ์ฒด ์„ค์ •์˜์—ญ]๊ณผ [์„œ๋น„์Šค ๋กœ์ง์˜์—ญ]์„ ๋ถ„๋ฆฌ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ณ  ๊ฐ์ฒด๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ˜๋‹ค.

๊ทธ ๋Œ€์‹  ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•ด์ฃผ๋Š” ์ปจํ…Œ์ด๋„ˆ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•˜๊ณ , ์˜์กด ๊ด€๊ณ„๋ฅผ ์ฐพ๊ธฐ ๋ฒˆ๊ฑฐ๋Ÿฌ์›Œ์ง€๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

class ContentWriter {

    FileReader reader;

    ContentWriter(FileReader reader) {
        this.reader = reader;
    }

    public void print() {
        String content = reader.readAll();
        System.out.println(content);
    }
}

 

 

๐Ÿ“Œ ์ƒ์†์€ ๋ถ€๋ชจ ํด๋ž˜์Šค ๊ตฌํ˜„์˜ ์žฌ์ •์˜๋ฅผ, ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์—ญํ• ๊ณผ ์ถ”์ƒํ™”๋งŒ ์ œ๊ณตํ•œ๋‹ค.

์ƒ์†์„ ์ด์šฉํ•˜๋ฉด ํด๋ž˜์Šค๋ฅผ ์‰ฝ๊ฒŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ€๋Šฅํ•˜๋ฉด ์ƒ์†์€ ํ”ผํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ํ”ผํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๋‹น์žฅ์€ ์ƒ์†์œผ๋กœ ๊น”๋”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋‚˜ ์š”๊ตฌ์‚ฌํ•ญ์ด ์ถ”๊ฐ€๋˜๊ณ  ์ฝ”๋“œ๊ฐ€ ์ˆ˜์ •๋˜๋ฉด ๋ถ€๋ชจํด๋ž˜์Šค๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค.

์ด ์ˆ˜์ •์œผ๋กœ ์ธํ•ด ๋ถ€๋ชจํด๋ž˜์Šค์—์„œ ๋ฌธ์ œ๊ฐ€ ์—†๋”๋ผ๋„, ์ž์‹ ํด๋ž˜์Šค์—์„œ๋„ ๋˜‘๊ฐ™์ด ๋ฌธ์ œ๊ฐ€ ์—†์Œ์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค.

๋˜๋Š” ์‚ฌ๋ฃŒ๋ฅผ ๋จน์ง€์•Š๋Š” ๋™๋ฌผ์ด ์žˆ๋‹ค๋ฉด? [๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•œ SUPER ๋ถ€๋ชจ ๋ฉ”์„œ๋“œ]๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด ๋ฌด์Šจ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์„๊นŒ?
์ธํ„ฐํŽ˜์ด์Šค๋Š” ์‹ค์ œ ๊ตฌํ˜„ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์—ญํ• (์ถ”์ƒํ™”, ์ด๋ฆ„)๋งŒ ์ œ๊ณตํ•œ๋‹ค. ๋‹ค์ค‘ ์ƒ์†ํ•˜๋”๋ผ๋„ ๋ณ„ ์ƒ๊ด€์—†๋‹ค.

๊ทธ๋ž˜์„œ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์›์น™์„ ์ž˜ ๋”ฐ๋ฅด๊ธฐ์œ„ํ•ด์„ , ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŽ์ด ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๋ฌผ๋ก  '์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ฐ”๋€Œ๊ฑฐ๋‚˜' , '๋ถ€๋ชจ ๊ฐ์ฒด์˜ ์ •๋ณด'๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋งŒ๋Šฅ์€ ์•„๋‹ˆ๋‹ค. 

โžก ๊ทธ๋ž˜์„œ ์ž๋ฐ”์—์„œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ(default, private)๋ฅผ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

โžก ๊ฐ์ฒด๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์ง€์•Š๊ณ , ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฑฐ์ณ ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ๋ฐ›๋Š” ์ž‘์—…์€ ์ถ”๊ฐ€์ ์ธ ๋น„์šฉ์ด ๋“ ๋‹ค๋Š”๊ฑธ ์•Œ๊ณ ์žˆ์ž.

 

 

๐Ÿ“Œ ๋‹คํ˜•์„ฑ์€ ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ธ์Šคํ„ด์Šค์— ๋”ฐ๋ผ ํ–‰์œ„๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.

๋‹คํ˜•์„ฑ์˜ ํ•ต์‹ฌ์€ ์—ญํ• ๊ณผ ๊ตฌํ˜„์˜ ๋ถ„๋ฆฌ์ด๋‹ค.

๋‹คํ˜•์„ฑ์„ ๊ณ ๋ คํ•˜์ง€์•Š๊ณ  ๋ฌด์ž‘์ • ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฑด, ์˜คํžˆ๋ ค ๋” ์•ˆ์ข‹์€ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

#1 ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์บก์Šํ™”, ์ถ”์ƒํ™”, ์ƒ์†, ๋‹คํ˜•์„ฑ... ๋งŽ์ด ๋“ค์–ด๋ดค์ง€๋งŒ, ์ •์ž‘ ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€์ง€ ์ž˜ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ํ•ด๋‹น ๊ธ€์—์„œ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ๊ฐœ๋…์ด ์™œ ์ƒ๊ฒผ๊ณ , ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ง€

jiwondev.tistory.com

 

 

๐Ÿ“Œ ๊ฐ์ฒด๊ฐ€ ์ž์‹ ์˜ ์†์„ฑ์— ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์„ ๊ตฌ์„ฑ(Composition)์ด๋ผ ํ•œ๋‹ค.

 

4-1 ์ƒ์†, ์ธํ„ฐํŽ˜์ด์Šค, ํด๋ž˜์Šค์˜ ๊ถŒํ•œ ์ตœ์†Œํ™”(+Java9 ๋ชจ๋“ˆ)

์ ‘๊ทผ์ œ์–ด์ž๋ฅผ ์ ๊ทน์ ์œผ๋กœ ํ™œ์šฉํ•˜๋ผ. (์ „๋ถ€๋‹ค Public์œผ๋กœ ๋งŒ๋“ค์ง€ ๋งˆ๋ผ) ์ž˜ ์„ค๊ณ„๋œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ชจ๋“  ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์™„๋ฒฝํžˆ ์ˆจ๊ฒจ, ๊ตฌํ˜„๊ณผ API๋ฅผ ๊น”๋”ํžˆ ๋ถ„๋ฆฌํ•œ๋‹ค. ์˜ค์ง API๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋‹ค๋ฅธ 

jiwondev.tistory.com

 

 

๐Ÿ“Œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” '๊ฐ์ฒด' ํ–‰์œ„๋ฅผ ๋ช…์‹œํ•˜๊ณ  ํ™•์ธํ•œ๋‹ค. ์˜์กด์„ฑ์€ ํ…Œ์ŠคํŠธ ๋”๋ธ”๋กœ ๋Œ€์ฒดํ•˜์ž.

์ฐธ๊ณ ๋กœ ํ…Œ์ŠคํŠธ ๋”๋ธ”์€ ์˜ํ™”๋ฐฐ์šฐ์˜ ์Šคํ„ดํŠธ ๋”๋ธ”(์Šคํ„ดํŠธ ๋Œ€์—ญ)์—์„œ ๋”ฐ์˜จ ๋ง์ด๋‹ค. ํ…Œ์ŠคํŠธ์šฉ ์ž„์‹œ ๊ฐ์ฒด.

 

๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ์™€ Test Double (+Mockist)

Mockito ๋ ˆํผ๋Ÿฐ์Šค https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html Mockito - mockito-core 3.12.4 javadoc Latest version of org.mockito:mockito-core https://javadoc.io/d..

jiwondev.tistory.com

 

 


[ #2. ์„œ๋น„์Šค ์ƒ์„ฑํ•˜๊ธฐ ]

ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด๋Š” ๋ณดํ†ต 2๊ฐ€์ง€๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค. [๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ ์žˆ๋Š” ๊ฐ์ฒด]์™€ [์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์„œ๋น„์Šค ๊ฐ์ฒด]

 

[์„œ๋น„์Šค ๊ฐ์ฒด]๋Š” ํ•œ๋ฒˆ ์ƒ์„ฑํ•˜๋ฉด ์—ฌ๋Ÿฌ๋ฒˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ž์‹ ์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๊ณ  ์ƒ๋ช…์ฃผ๊ธฐ๋„ ๋‹จ์ˆœํ•˜๋‹ค.

[๋ฐ์ดํ„ฐ ๊ฐ์ฒด]๋Š” ์ž์‹ ์„ ์ด์šฉํ•ด ์ž‘์—…์„ ์™„๋ฃŒํ•œ๋‹ค. ์„œ๋น„์Šค๊ฐ€ ์ž‘๋™ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์žฌ๋ฃŒ์ด๋ฉฐ ์ƒ๋ช… ์ฃผ๊ธฐ๊ธฐ ๋ณต์žกํ•˜๋‹ค.

๐Ÿ“Œ ์˜์กด์„ฑ๊ณผ ์„ค์ • ๊ฐ’์„ ์ƒ์„ฑ์ž ์ธ์ž๋ฅผ ์ด์šฉํ•ด ๋ช…์‹œ์ ์œผ๋กœ, ํ•œ๋ฒˆ์— ์ œ๊ณตํ•˜์ž.

[์„ค์ • ์˜์—ญ]๊ณผ [์„œ๋น„์Šค ์˜์—ญ]์„ ๋ถ„๋ฆฌํ•˜์ž. ๋•Œ๋ก  ๊ฐ์ฒด์˜ ์˜์กด์„ฑ๊ณผ ํ•จ๊ป˜ ํŒŒ์ผ ์ €์žฅ ์œ„์น˜๋‚˜ ํ‚ค๊ฐ’๋“ฑ์„ ์„ค์ •๊ฐ’์œผ๋กœ ๊ฐ–๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„ค์ •๊ฐ’ ๋˜ํ•œ ์ƒ์„ฑ์ž ์ธ์ž๋กœ ์ฃผ์ž…๋ฐ›์ž.

class FileLogger {

    private String logFilePath;
    Formatter formatter;
    
    FileLogger(Formatter formatter, String filePath) {
        this.formatter = formatter;
        this.logFilePath = filePath; // ์„ค์ • ๊ฐ’์„ ์ฃผ์ž…๋ฐ›์•„ ๊ฐ์ฒด์˜ ์—ญํ• ์„ ๋‚˜๋ˆ„์ž.
    }
}

* ์ƒ์„ฑ์ž๊ฐ€ ์•„๋‹Œ ์ˆ˜์ •์ž(Setter)๋กœ ์ฃผ์ž…ํ•˜๋ฉด ์–ด๋Š์‹œ์ ์— ์ฃผ์ž…๋˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ณ , ์ค‘๊ฐ„์— ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์ƒ๊ธด๋‹ค.

 

 

๐Ÿ“Œ ์ง์ด ์žˆ๋Š” ์„ค์ • ๊ฐ’์€ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด์„œ ์ฃผ์ž.

์•„์ด๋””์™€ ํŒจ์Šค์›Œ๋“œ์ฒ˜๋Ÿผ ํ•ญ์ƒ ๊ฐ™์ด ๋‹ค๋‹ˆ๋Š” ๊ฐ’๋“ค์„ ๋”ฐ๋กœ ์ฃผ์ž…ํ•˜๋ฉด ์ฝ”๋“œ์˜ ์‘์ง‘๋ ฅ์ด ๋–จ์–ด์ง€๊ณ  ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฐ’๋“ค์€ ๊ฐ์ฒด์— ๋‹ด์•„์„œ ์ œ๊ณตํ•˜๋„๋ก ํ•˜์ž.

@Getter
final class UserData {
// ๊ฐ’ ๊ฐ์ฒด๋Š” ์ƒ์†ํ•  ์ผ์ด ์—†๋‹ค.
    private String username;
    private String password;

}

class ApiClient {
    private User user;

//  public ApiClient(String username, String password) โŒ
    public ApiClient(User user) {
        this.user = user;
    }
}

 

 

๐Ÿ“Œ ํ•„์š”ํ•œ ๊ฒƒ์˜ ์œ„์น˜(Locate)๊ฐ€ ์•„๋‹ˆ๋ผ ํ•„์š”ํ•œ ๊ฒƒ ์ž์ฒด๋ฅผ ์ฃผ์ž…ํ•˜๋ผ.

๋Œ€๋ถ€๋ถ„์˜ ๋ณต์žกํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋Š” ๋ชจ๋“  ์„œ๋น„์Šค์™€ ์„ค์ •๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋Š” ํŠน๋ณ„ํ•œ ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ํ”ํžˆ ์ด๋ฅผ ์„œ๋น„์Šค ์œ„์น˜ ์ง€์ •์ž(Service Locator), ๊ฐ์ฒด ๊ด€๋ฆฌ์ž(Manager), ๋“ฑ๋ก์ž(Registry), ์•ฑ ์ปจํ…Œ์ด๋„ˆ(Container)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

 

๊ทธ๋ž˜์„œ ์ด๋Ÿฌํ•œ ๊ด€๋ฆฌ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์œ ํ˜น์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์•„์˜ˆ ์ปจํ…Œ์ด๋„ˆ ์ž์ฒด๋ฅผ ์ฃผ์ž…ํ•ด๋ฒ„๋ฆฌ๋Š” ๋ฐฉ๋ฒ•.

class HomeController {

    private ServiceLocator locator;

    public HomeController(ServiceLocator locator) {
        this.locator = locator; // ์–ธ์ œ๋“ ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ž์ฒด๋ฅผ ๋ฐ›๋Š”๋‹ค.
    }
    
    public void function(){
        // ๊ทธ๋ฆฌ๊ณ  ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด ๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค...?
        User user = this.locator.get(EntityManager.className)
            .getRepository(User.className)
            .getById(request.get('userId'));
        
        ...
    }
}

์ด ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ์ข‹์ง€์•Š๋‹ค.

1. [์„œ๋น„์Šค] ์—์„œ [์„ค์ • ์ฝ”๋“œ]๋ฅผ ๋‹ค๋ค„์•ผ ํ•œ๋‹ค. ์• ์ดˆ์— User ์˜์กด์„ฑ์„ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ์„œ๋น„์Šค ๊ฐ์ฒด๊ฐ€ ์•Œ์•„์•ผ ํ•œ๋‹ค.

2. Side Effect ๋ฐœ์ƒ โžก ํ•ด๋‹น ์„œ๋น„์Šค๊ฐ€ ํ•„์š”ํ•˜์ง€์•Š๋Š” ๋‹ค๋ฅธ ์˜์กด์„ฑ์„ ๊ฐ€์ ธ์™€์„œ ๋งˆ์Œ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

3. ์„œ๋น„์Šค ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง„ ์˜์กด์„ฑ์ด ๋ฌด์—‡์ธ์ง€ ์•Œ๊ธฐ ์–ด๋ ต๋‹ค. '๋ช…์‹œ์ ์œผ๋กœ ์˜์กด์„ฑ์„ ๊ฐ€์ ธ์˜จ๋‹ค' ๋ผ๋Š” ์˜๋ฏธ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ผ.

 

ํ•„์š”ํ•œ ๊ฒƒ์˜ ์œ„์น˜(Locator, Container)๋ฅผ ์ฃผ์ž…ํ•˜์ง€ ๋ง๊ณ  ํ•„์š”ํ•œ ๊ฒƒ ์ž์ฒด๋ฅผ ์ฃผ์ž…ํ•˜๋ผ. ๊ทธ๋Ÿผ ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๋‹ค.

์œ„์น˜๋ผ๊ณ  ์ ์€ ์ด์œ ๋Š” ์ปจํ…Œ์ด๋„ˆ๋ฟ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๊ณณ์— ์ ์šฉ๋˜๋Š” ๋ง์ด๋ผ์„œ ๊ทธ๋ ‡๋‹ค. ํ•„์š”ํ•œ ์˜์กด์„ฑ๋งŒ์„ ์ฃผ์ž…ํ•˜๋ผ.

class ApiClient {
    private User user;
    private ResponseFactory responseFactory;

    // ์˜์กด๊ด€๊ณ„๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
    public ApiClient(User user, ResponseFactory responseFactory) {
        this.user = user;
        this.responseFactory = responseFactory;
    }
}

 

Q. ๊ฐ€์ ธ์˜ค๋ ค๋Š” ์ปจํ…Œ์ด๋„ˆ(๋˜๋Š” ๊ฐ์ฒด)์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด์š”? ์ง์„ ์ง€์–ด์„œ ์ „๋‹ฌํ•˜๋ผ๋ฉด์„œ์š”?

์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ์ž˜ ์—†๋‹ค. ์ด๋Š” ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์กด์žฌํ•  ํ•„์š”๊ฐ€ ์—†๊ฑฐ๋‚˜ ํ•œ ๊ฐ์ฒด๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ์ง€๊ณ  ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

ํ•œ ๊ฐ์ฒด๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋Š”๊ฐ€? ๊ฐ์ฒด์˜ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•ด๋ณด์ž.

// EntityManager๋Š” ์ปจํ…Œ์ด๋„ˆ ๊ฐ์ฒด์ด๋‹ค. ์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” EntityManager์˜ ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user = this.entityManager.getRepository(...).getUser(...);
user.changePassword(newPassword);

this.entityManager.flush();
// ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ํ•œ ๊ฐ์ฒด๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.
// EntityManager์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ํ•œ ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค.
user = this.entityManager.getRepository(...).getUser(...);
user.changePassword(newPassword);

this.userRepository.save(user) // flush() ์ฑ…์ž„์„ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ๋ถ„๋ฆฌ

 

 

๐Ÿ“Œ ์„œ๋น„์Šค๋Š” ์ƒ์„ฑ ํ›„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅ ํ•ด์•ผํ•œ๋‹ค. ๋ฉ”์„œ๋“œ์˜ ํ–‰์œ„๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์•ˆ๋œ๋‹ค.

  • ์„ ํƒ์ ์ธ ์˜์กด์„ฑ ๊ฐ™์€๊ฑด ์—†๋‹ค. ๋ชจ๋“  ์ƒ์„ฑ์ž์˜ ์ธ์ž๋Š” ํ•„์ˆ˜์—ฌ์•ผ ํ•œ๋‹ค.
  • ์ฆ‰ ์„œ๋น„์Šค ๊ฐ์ฒด๋Š” ์ƒ์„ฑ ํ›„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅ(immutable)ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ผ.

๊ฐ์ฒด๋ฅผ ๋ถˆ์™„์ „ํ•œ ์ƒํƒœ๋กœ ์ƒ์„ฑํ•˜์ง€ ๋งˆ๋ผ. null์„ ์‚ฝ์ž…ํ•ด๋‘๊ณ  ์ค‘๊ฐ„์— setter๋กœ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑด ๋งค์šฐ ์œ„ํ—˜ํ•œ ํ–‰์œ„์ด๋‹ค.

์˜์กด์„ฑ์€ ํ•„์š”ํ•˜๊ฑฐ๋‚˜, ํ•„์š”ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์•„๋ฌด๋Ÿฐ ๋™์ž‘์„ ํ•˜์ง€ ์•Š๋Š” ๋”๋ฏธ(dummy)๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ผ. ์„œ๋น„์Šค์˜ ๋™์ž‘์„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ผ.

final class NullLogger implements Logger {

    public void log(String message) {
        // ์•„๋ฌด๋Ÿฐ ๋™์ž‘๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
    }
}

์„œ๋น„์Šค๋Š” ์ƒ์„ฑ ํ›„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•ด์•ผํ•œ๋‹ค. ๋งŒ์•ฝ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด ์†์„ฑ์„ ๋ฐ”๊ฟ”์„œ ๋ฉ”์„œ๋“œ์˜ ํ–‰์œ„๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์ƒˆ๋กœ์šด ์„œ๋น„์Šค ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋งž๋‹ค.

 

Q. ๋งŒ์•ฝ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋‹ค๋ฅธ ์ž‘์—… ๋ฐ์ดํ„ฐ๊ฐ’์„ ๊ฐ€์ ธ์•ผํ•œ๋‹ค๋ฉด?

๊ทธ๋•Œ๋Š” ์ƒ์„ฑ์ž๋‚˜ Setter๊ฐ€ ์•„๋‹Œ ๋ฉ”์„œ๋“œ๋กœ ์ฃผ์ž…๋ฐ›๋Š” ๊ฒƒ์ด ๋งž๋‹ค.

[ ์ž‘์—… ๊ด€๋ จ ๋ฐ์ดํ„ฐ ] ๋Š” ์˜์กด์„ฑ์ด ์•„๋‹ˆ๋‹ค. ํ•„๋“œ๋กœ ์ฃผ์ž…ํ•œ๋‹ค๋ฉด ๋ชจ๋“  ์ž‘์—…์— ๋Œ€ํ•ด ๋‹ค์‹œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

final class ContractRepository{

    private Session session; // ์ƒํƒœ ์ •๋ณด๋ฅผ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ์ž ์ฃผ์ž…์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

    public ContractRepository(Session session) {
        this.session = session;
    }
    
    public List getAllContracts(){
        return this.select()
            // HTTP ์„ธ์…˜์€ ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์ง„๋‹ค.
            // getAllContracts() ์˜ ์ธ์Šคํ„ด์Šค ๋˜ํ•œ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜์—†๋‹ค. ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.
            .where([this.session.userId, this.session.companyId])
            .getResult();
    }
}

์ž‘์—… ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฉ”์„œ๋“œ๋กœ ์ฃผ์ž…๋ฐ›๋Š” ๊ฒƒ์ด ๋งž๋‹ค. 

final class ContractRepository{

    public ContractRepository() {}
     
    public List getAllContracts(String userId, String companyId){
    // ๋ฉ”์„œ๋“œ๋กœ ์ž‘์—… ๋ฐ์ดํ„ฐ์˜ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›๋Š”๋‹ค.
    // ์ด์ œ ์ด ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ๋Š” ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
        return this.select()
            .where([userId, companyId])
            .getResult();
    }
}

 

๐Ÿ“Œ ๋ณต์žกํ•œ ํ•จ์ˆ˜๋ฅผ ๊ฐ์ฒด ์˜์กด์„ฑ์œผ๋กœ ๋ฐ”๊พธ์–ด๋ผ.

๋•Œ๋•Œ๋กœ ์˜์กด์„ฑ์€ ํ•จ์ˆ˜ ์•ˆ์— ์ˆจ์–ด์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

๋ณดํ†ต json_enode() ๋‚˜ simplexml_load_file() ๊ฐ™์€ ์ด๋ฆ„์˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์ด์— ์†ํ•˜๋Š”๋ฐ, ์ด๋Ÿฐ ํ•จ์ˆ˜๋“ค์„ ๊ฐ์‹ธ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค๊ณ , ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์•„๋ผ.

 

์„œ๋น„์Šค์— ํ•„์š”์—†๋Š” ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋‚˜ ์„ค์ •๋“ค์˜ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์˜์กด์„ฑ์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜์—ฌ ์„œ๋น„์Šค ์ฝ”๋“œ์˜ ์ˆ˜์ • ์—†์ด ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

final class JsonEncoder {
    public String encode(...){
        try {
            json_encode(); // ์˜์กด์„ฑ์ด ์žˆ๋Š” ๋ฉ”์„œ๋“œ
            
        } catch (RuntimeException runtimeException) {
            // ์ด๋ ‡๊ฒŒ ์˜ˆ์™ธ๋ฅผ ๊ฐ์‹ธ ๋” ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
            throw new RuntimeException("Failed to encode data : " + data);
        }
        
    }
}
final class Hello {
    private JsonEncoder jsonEncoder;

    public Hello(JsonEncoder jsonStringEncoder) {
        this.jsonEncoder = jsonStringEncoder; // ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›๋Š”๋‹ค.
    }
    
    public void service(){
    	this.jsonEncoder.encode(...); // ๊ฐ์ฒด์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
    }
}

 

๋ฌผ๋ก  ๊ทธ๋ ‡๋‹ค๊ณ  String.replace("") ๊ฐ™์€ ์ธ๋ผ์ธ ํ•จ์ˆ˜๊นŒ์ง€ ๋ชจ๋‘ ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ๋Š” ๋ณ€ํƒœ ์ง“์„ ํ•˜๋ผ๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค.

  • ์ด ์˜์กด์„ฑ์œผ๋กœ ์ œ๊ณตํ•œ ํ–‰์œ„๋ฅผ ๋‚˜์ค‘์— ๋Œ€์ฒดํ•˜๊ฑฐ๋‚˜ ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์€๊ฐ€?
  • ์ด ์˜์กด์„ฑ์˜ ํ–‰์œ„๊ฐ€ ๋ณต์žกํ•ด์„œ ๋‹จ์ง€ ์ฝ”๋“œ ๋ช‡ ์ค„๋กœ๋Š” ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด๊ฐ€?
  • ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ๊ธฐ๋ณธํƒ€์ž…(primitive) ๊ฐ’ ๋Œ€์‹  ๊ฐ์ฒด๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?

์ด์— ํ•ด๋‹นํ•œ๋‹ค๋ฉด ๊ฐ์ฒด ์˜์กด์„ฑ์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ  ๋‹จ์œ„ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์šฉ์ดํ•˜๋‹ค๋Š” ์žฅ์ ๋„ ์ƒ๊ธด๋‹ค. ํ•ต์‹ฌ์€ ์ฑ…์ž„์˜ ๋ถ„๋ฆฌ. ์ฆ‰ ์„œ๋น„์Šค ์ฝ”๋“œ๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ , ์„ค์ •์„ ๋ณ€๊ฒฝ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

* ๋‹จ ์‹œ์Šคํ…œ ํ˜ธ์ถœ ํ•จ์ˆ˜๋Š” ์˜ˆ์™ธ์ด๋‹ค. ์‹œ์Šคํ…œ ํ˜ธ์ถœ์€ ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ์ง€ ๋ง๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๐Ÿ“Œ ์ƒ์„ฑ์ž๋Š” ์†์„ฑ์„ ํ• ๋‹นํ•˜๊ณ , ์ธ์ž์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ์ผ์—๋งŒ ์‚ฌ์šฉํ•˜๋ผ.

์„œ๋น„์Šค ์ƒ์„ฑ์€ ์ธ์ž๋ฅผ ์ฃผ์ž…ํ•˜๊ณ  ์œ ํšจ์„ฑ์„ ํ™•์ธํ•˜๋Š” ์ ˆ์ฐจ์ด๋‹ค. ์ฆ‰ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ค€๋น„ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

์‹ค์ œ ์ž‘์—…์€ ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ์—์„œ ์ด๋ฃจ์–ด์ ธ์•ผํ•œ๋‹ค. ์ƒ์„ฑ์ž์—์„œ ์ž‘์—…์„ ํ•˜์ง€๋งˆ๋ผ.

final class FileLogger implements Logger {

    private String logFileDir;

    public FileLogger(String logFileDir) {
        this.logFileDir = logFileDir;
        
        // ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
        if (!is_dir(logFileDir)) {
            mkdir(logFileDir, 0777, true);
        }
        ...
    }
}

 

์ด๋ ‡๊ฒŒ ์ƒ์„ฑ์‹œ์ ์— ํ•ด์ค˜์•ผํ•  ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด, ์ƒ์„ฑ์ž๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค์ง€ ๋ง๊ณ  Factory ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋ผ.

final class FileLogger implements Logger {

    private String logFileDir;

    public FileLogger(String logFileDir) {
        this.logFileDir = logFileDir;
    }
}
final class LoggerFactory{

    public static FileLogger createFileLogger(String logFilePath) {
        if (!is_dir(logFileDir)) {
            mkdir(logFileDir, 0777, true);
        }
        ... // ์„ค์ • ์ž‘์—…
        return fileLogger;
    }
    
}

 

๋งŒ์•ฝ ์•„๋ž˜์™€ ๊ฐ™์ด Factory ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์• ๋งคํ•œ ๊ฒฝ์šฐ๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์™ธ๋ถ€์˜ Factory ํด๋ž˜์Šค์—์„œ ํ• ๋‹นํ•˜๊ธฐ๋Š” ์• ๋งคํ•˜๋‹ค. ํ• ๋‹น ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๊ฒŒ ๋˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ์ผ์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

final class Mailer{

    private Translator translator;
    private String defaultText;

    public Mailer(Translator translator, String locale) {
        this.translator = translator; // ๋ฐ˜๋“œ์‹œ translator๋ฅผ ๋จผ์ € ํ• ๋‹นํ•ด์•ผํ•œ๋‹ค.
        this.defaultText = this.translator.translate("default", locale)
    }
}

 

ํŠน์ • ์ˆœ์„œ๋ฅผ ์ง€์ผœ์„œ ํ• ๋‹นํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ์ƒ์„ฑ์ž์—๋Š” ๋ฌด์–ธ๊ฐ€ ์ถ”๊ฐ€ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.

 

์ด๋•Œ๋Š” ๋‚ด ์ฝ”๋“œ์˜ ์„ค๊ณ„๊ฐ€ ์ž˜๋ชป๋œ๊ฒŒ ์•„๋‹Œ๊ฐ€ ํ•œ๋ฒˆ ๋” ๊ณ ๋ฏผํ•ด๋ณด์ž. ์ด ๊ฒฝ์šฐ ์œ„์—์„œ ๋งํ–ˆ๋“ฏ์ด ์‚ฌ์šฉ์ž์˜ ์œ„์น˜(Locale)์ •๋ณด๋Š” ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ์ด๋‹ค. ์ƒ์„ฑ์ž๋กœ ์ฃผ์ž… ๋ฐ›๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค.

 

๐Ÿ“Œ ์ธ์ž๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ์ผ์œผ์ผœ๋ผ.

์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ์ฒด์˜ ์ธ์ž๋ฅผ ํ™•์ธํ•˜๋„๋ก ๋งŒ๋“ค์ง€๋งˆ๋ผ. ์ƒ์„ฑ์‹œ์ ์— ์ธ์ž๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๋‹ค๋ฉด ํŠน์ • ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ InvalidArgumentException ๊ฐ™์€ ์˜ˆ์™ธ๋ฅผ ์ผ์œผ์ผœ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ•์ œํ•˜๋„๋ก ๋งŒ๋“ค์–ด๋ผ.

๋Ÿฐํƒ€์ž„ ์˜ˆ์™ธ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด, ์–ธ์–ด์—์„œ ์ œ๊ณตํ•˜๋Š” ํ‘œ์ค€ ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ™•์žฅ์„ฑ์ด๋‚˜ ๊ฐ€๋…์„ฑ์— ์ข‹๋‹ค.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ