๋””์ž์ธ ํŒจํ„ด/GOF

๐Ÿ’  ํ”„๋ก์‹œ(Proxy) ํŒจํ„ด - ์™„๋ฒฝ ๋งˆ์Šคํ„ฐํ•˜๊ธฐ

์ธํŒŒ_ 2023. 1. 12. 07:05

Proxy-Pattern
Proxy-Pattern

Proxy Pattern

ํ”„๋ก์‹œ ํŒจํ„ด(Proxy Pattern)์€ ๋Œ€์ƒ ์›๋ณธ ๊ฐ์ฒด๋ฅผ ๋Œ€๋ฆฌํ•˜์—ฌ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•จ์œผ๋กœ์จ ๋กœ์ง์˜ ํ๋ฆ„์„ ์ œ์–ดํ•˜๋Š” ํ–‰๋™ ํŒจํ„ด์ด๋‹ค.

ํ”„๋ก์‹œ(Proxy)์˜ ์‚ฌ์ „์ ์ธ ์˜๋ฏธ๋Š” '๋Œ€๋ฆฌ์ธ'์ด๋ผ๋Š” ๋œป์ด๋‹ค. ์ฆ‰, ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์–ด๋–ค ์ผ์„ ๋Œ€์‹  ์‹œํ‚ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š”๋ฐ, ์ด๋ฅผ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ์ ‘๋ชฉํ•ด๋ณด๋ฉด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์“ฐ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ค‘๊ฐ„์— ํ”„๋ก์‹œ(๋Œ€๋ฆฌ์ธ)์„ ๊ฑฐ์ณ์„œ ์“ฐ๋Š” ์ฝ”๋“œ ํŒจํ„ด์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๋Œ€์ƒ ๊ฐ์ฒด(Subject)์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๋Œ€์ƒ ๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๊ธฐ ์ „์— ํ”„๋ก์‹œ(Proxy) ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ ‘๊ทผํ•œ ํ›„ ์ถ”๊ฐ€์ ์ธ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•œ๋’ค ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค.

Proxy-Pattern

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

  1. ๋ณด์•ˆ(Security) : ํ”„๋ก์‹œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ๊ฐ€ ๊ธ์ •์ ์ธ ๊ฒฝ์šฐ์—๋งŒ ์š”์ฒญ์„ ๋Œ€์ƒ์œผ๋กœ ์ „๋‹ฌํ•œ๋‹ค.
  2. ์บ์‹ฑ(Caching) : ํ”„๋ก์‹œ๊ฐ€ ๋‚ด๋ถ€ ์บ์‹œ๋ฅผ ์œ ์ง€ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๊ฐ€ ์บ์‹œ์— ์•„์ง ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋Œ€์ƒ์—์„œ ์ž‘์—…์ด ์‹คํ–‰๋˜๋„๋ก ํ•œ๋‹ค.
  3. ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ(Data validation) : ํ”„๋ก์‹œ๊ฐ€ ์ž…๋ ฅ์„ ๋Œ€์ƒ์œผ๋กœ ์ „๋‹ฌํ•˜๊ธฐ ์ „์— ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•œ๋‹ค.
  4. ์ง€์—ฐ ์ดˆ๊ธฐํ™”(Lazy initialization) : ๋Œ€์ƒ์˜ ์ƒ์„ฑ ๋น„์šฉ์ด ๋น„์‹ธ๋‹ค๋ฉด ํ”„๋ก์‹œ๋Š” ๊ทธ๊ฒƒ์„ ํ•„์š”๋กœ ํ• ๋•Œ๊นŒ์ง€ ์—ฐ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  5. ๋กœ๊น…(Logging) : ํ”„๋ก์‹œ๋Š” ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๊ณผ ์ƒ๋Œ€ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ธํ„ฐ์…‰ํŠธํ•˜๊ณ  ์ด๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.
  6. ์›๊ฒฉ ๊ฐ์ฒด(Remote objects) : ํ”„๋ก์‹œ๋Š” ์›๊ฒฉ ์œ„์น˜์— ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋กœ์ปฌ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋ก์‹œ ํŒจํ„ด ๊ตฌ์กฐ

ํ”„๋ก์‹œ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ๊ฐœ์ฒด์ด๋‹ค. ์—ฌ๊ธฐ์„œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ(Subject)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ํ”„๋ก์‹œ์™€ ๋Œ€์ƒ์€ ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค์™€ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜๋„๋ก ๋ฐ”๊ฟ€์ˆ˜ ์žˆ๋‹ค.

Proxy-Pattern

  • Subject : Proxy์™€ RealSubject๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ๋Š” ์ธํ„ฐํŽ˜์ด์Šค (๋‹คํ˜•์„ฑ)
    • ๋Œ€์ƒ ๊ฐ์ฒด์™€ ํ”„๋ก์‹œ ์—ญํ• ์„ ๋™์ผํ•˜๊ฒŒ ํ•˜๋Š” ์ถ”์ƒ ๋ฉ”์†Œ๋“œ operation() ๋ฅผ ์ •์˜ํ•œ๋‹ค.
    • ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ๋Š” Proxy ์—ญํ• ๊ณผ RealSubject ์—ญํ• ์˜ ์ฐจ์ด๋ฅผ ์˜์‹ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • RealSubject : ์›๋ณธ ๋Œ€์ƒ ๊ฐ์ฒด
  • Proxy : ๋Œ€์ƒ ๊ฐ์ฒด(RealSubject)๋ฅผ ์ค‘๊ณ„ํ•  ๋Œ€๋ฆฌ์ž ์—ญํ• 
    • ํ”„๋ก์‹œ๋Š” ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ํ•ฉ์„ฑ(composition)ํ•œ๋‹ค.
    • ํ”„๋ก์‹œ๋Š” ๋Œ€์ƒ ๊ฐ์ฒด์™€ ๊ฐ™์€ ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉฐ, ๋ณ„๋„์˜ ๋กœ์ง์„ ์ˆ˜ํ–‰ ํ• ์ˆ˜ ์žˆ๋‹ค (์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ ๋ฉ”์†Œ๋“œ)
    • ํ”„๋ก์‹œ๋Š” ํ๋ฆ„์ œ์–ด๋งŒ ํ•  ๋ฟ ๊ฒฐ๊ณผ๊ฐ’์„ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉด ์•ˆ ๋œ๋‹ค.
  • Client : Subject ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ์ด์šฉ.
    • ํด๋ผ์ด์–ธํŠธ๋Š” ํ”„๋ก์‹œ๋ฅผ ์ค‘๊ฐ„์— ๋‘๊ณ  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด์„œ RealSubject์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๋‹ค.

ํ”„๋ก์‹œ ํŒจํ„ด ์ข…๋ฅ˜

Proxy ํŒจํ„ด์€ ๋‹จ์ˆœํ•˜๋ฉด์„œ๋„ ์ž์ฃผ ์“ฐ์ด๋Š” ํŒจํ„ด์ด๋ฉฐ, ๊ทธ ํ™œ์šฉ ๋ฐฉ์‹๋„ ๋‹ค์–‘ํ•˜๋‹ค. ๊ฐ™์€ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ผ๋„ ์–ด๋– ํ•œ ๋กœ์ง์„ ์งœ๋Š๋ƒ์— ๋”ฐ๋ผ ๊ทธ ํ™œ์šฉ๋„๋Š” ์ฒœ์ฐจ๋งŒ๋ณ„์ด ๋œ๋‹ค. Proxy ํŒจํ„ด์˜ ๊ธฐ๋ณธํ˜•์„ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ณ€ํ˜•ํ•˜๋Š๋ƒ์— ๋”ฐ๋ผ ํ”„๋ก์‹œ ์ข…๋ฅ˜๊ฐ€ ๋‚˜๋‰˜์–ด์ง€๊ฒŒ ๋œ๋‹ค.

 

๊ธฐ๋ณธํ˜• ํ”„๋ก์‹œ (Normal Proxy)

interface ISubject {
    void action();
}

class RealSubject implements ISubject {
    public void action() {
        System.out.println("์›๋ณธ ๊ฐ์ฒด ์•ก์…˜ !!");
    }
}
class Proxy implements ISubject {
    private RealSubject subject; // ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ composition

    Proxy(RealSubject subject) {
        this.subject = subject;
    }

    public void action() {
        subject.action(); // ์œ„์ž„
        /* do something */
        System.out.println("ํ”„๋ก์‹œ ๊ฐ์ฒด ์•ก์…˜ !!");
    }
}

class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy(new RealSubject());
        sub.action();
    }
}

Proxy-Pattern

 

๊ฐ€์ƒ ํ”„๋ก์‹œ (Virtual Proxy)

  • ์ง€์—ฐ ์ดˆ๊ธฐํ™” ๋ฐฉ์‹
  • ๊ฐ€๋” ํ•„์š”ํ•˜์ง€๋งŒ ํ•ญ์ƒ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌ๋˜์–ด ์žˆ๋Š” ๋ฌด๊ฑฐ์šด ์„œ๋น„์Šค ๊ฐ์ฒด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ
  • ์ด ๊ตฌํ˜„์€ ์‹ค์ œ ๊ฐ์ฒด์˜ ์ƒ์„ฑ์— ๋งŽ์€ ์ž์›์ด ์†Œ๋ชจ ๋˜์ง€๋งŒ ์‚ฌ์šฉ ๋นˆ๋„๋Š” ๋‚ฎ์„ ๋•Œ ์“ฐ๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • ์„œ๋น„์Šค๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹ ์— ๊ฐ์ฒด ์ดˆ๊ธฐํ™”๊ฐ€ ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์‹œ์ ์— ์ดˆ๊ธฐํ™”๋ ์ˆ˜ ์žˆ๋„๋ก ์ง€์—ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
class Proxy implements ISubject {
    private RealSubject subject; // ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ composition

    Proxy() {
    }

    public void action() {
    	// ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ ์š”์ฒญ(action(๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ)์ด ๋“ค์–ด ์™”์„ ๋•Œ ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
        if(subject == null){
            subject = new RealSubject();
        }
        subject.action(); // ์œ„์ž„
        /* do something */
        System.out.println("ํ”„๋ก์‹œ ๊ฐ์ฒด ์•ก์…˜ !!");
    }
}

class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy();
        sub.action();
    }
}

 

๋ณดํ˜ธ ํ”„๋ก์‹œ (Protection Proxy)

  • ํ”„๋ก์‹œ๊ฐ€ ๋Œ€์ƒ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ž์›์œผ๋กœ์˜ ์—‘์„ธ์Šค ์ œ์–ด(์ ‘๊ทผ ๊ถŒํ•œ)
  • ํŠน์ • ํด๋ผ์ด์–ธํŠธ๋งŒ ์„œ๋น„์Šค ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒฝ์šฐ
  • ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ์˜ ์ž๊ฒฉ ์ฆ๋ช…์ด ๊ธฐ์ค€๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์„œ๋น„์Šค ๊ฐ์ฒด์— ์š”์ฒญ์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
class Proxy implements ISubject {
    private RealSubject subject; // ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ composition
    boolean access; // ์ ‘๊ทผ ๊ถŒํ•œ

    Proxy(RealSubject subject, boolean access) {
        this.subject = subject;
        this.access = access;
    }

    public void action() {
        if(access) {
            subject.action(); // ์œ„์ž„
            /* do something */
            System.out.println("ํ”„๋ก์‹œ ๊ฐ์ฒด ์•ก์…˜ !!");
        }
    }
}

class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy(new RealSubject(), false);
        sub.action();
    }
}

 

๋กœ๊น… ํ”„๋ก์‹œ (Logging Proxy)

  • ๋Œ€์ƒ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋กœ๊น…์„ ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ
  • ํ”„๋ก์‹œ๋Š” ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „๋‹ฌํ•˜๊ธฐ ์ „์— ๋กœ๊น…์„ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์žฌ์ •์˜ํ•œ๋‹ค.
class Proxy implements ISubject {
    private RealSubject subject; // ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ composition

    Proxy(RealSubject subject {
        this.subject = subject;
    }

    public void action() {
        System.out.println("๋กœ๊น…..................");
        
        subject.action(); // ์œ„์ž„
        /* do something */
        System.out.println("ํ”„๋ก์‹œ ๊ฐ์ฒด ์•ก์…˜ !!");

        System.out.println("๋กœ๊น…..................");
    }
}

class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy(new RealSubject());
        sub.action();
    }
}

 

์›๊ฒฉ ํ”„๋ก์‹œ (Remote Proxy)

  • ํ”„๋ก์‹œ ํด๋ž˜์Šค๋Š” ๋กœ์ปฌ์— ์žˆ๊ณ , ๋Œ€์ƒ ๊ฐ์ฒด๋Š” ์›๊ฒฉ ์„œ๋ฒ„์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ
  • ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์ „๋‹ฌํ•˜์—ฌ ๋„คํŠธ์›Œํฌ์™€ ๊ด€๋ จ๋œ ๋ถˆํ•„์š”ํ•œ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ’๋งŒ ๋ฐ˜ํ™˜
  • ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ˆ ์›๊ฒฉ์ด๋“  ๋กœ์ปฌ์ด๋“  ์‹ ๊ฒฝ ์“ธ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ, ํ”„๋ก์‹œ๋Š” ์ง„์งœ ๊ฐ์ฒด์™€ ํ†ต์‹ ์„ ๋Œ€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.

Proxy-Pattern
https://blogshine.tistory.com/17

์ฐธ๊ณ ๋กœ ํ”„๋ก์‹œ๋ฅผ ์Šคํ„ฐ๋ธŒ๋ผ๊ณ ๋„ ๋ถ€๋ฅด๋ฉฐ, ํ”„๋ก์‹œ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ ๋ช…๋ น์„ ์ดํ•ดํ•˜๊ณ  ์ ํ•ฉํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๋ณด์กฐ๊ฐ์ฒด๋ฅผ ์Šค์ผˆ๋ ˆํ†ค์ด๋ผ ํ•œ๋‹ค.

 

์บ์‹ฑ ํ”„๋ก์‹œ (Caching Proxy)

  • ๋ฐ์ดํ„ฐ๊ฐ€ ํฐ ๊ฒฝ์šฐ ์บ์‹ฑํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ ์œ ๋„
  • ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์˜ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๊ณ  ์ด ์บ์‹œ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌ
[ HTTP Proxy ]

HTTP Proxy๋Š” ์›น์„œ๋ฒ„์™€ ๋ธŒ๋ผ์šฐ์ € ์‚ฌ์ด์—์„œ ์›น ํŽ˜์ด์ง€์˜ ์บ์‹ฑ์„ ์‹คํ–‰ํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด์ด๋‹ค. ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์–ด๋–ค ์›น ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•  ๋•Œ ์ง์ ‘ ์›น ์„œ๋ฒ„์—์„œ ๊ทธ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ , HTTP Proxy๊ฐ€ ์บ์‰ฌํ•ด์„œ ์–ด๋–ค ํŽ˜์ด์ง€๋ฅผ ๋Œ€์‹ ํ•ด์„œ ์ทจ๋“ํ•œ๋‹ค. ๋งŒ์ผ ์ตœ์‹  ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ํŽ˜์ด์ง€์˜ ์œ ํšจ๊ธฐ๊ฐ„์ด ์ง€๋‚ฌ์„ ๋•Œ ์›น ์„œ๋ฒ„์— ์›น ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ง€๋Ÿฌ ๊ฐ„๋‹ค.
์ด๋ฅผ ํŒจํ„ด์œผ๋กœ ๋”ฐ์ ธ๋ณด๋ฉด, ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ Client ์—ญํ• , HTTP Proxy๊ฐ€ Proxy ์—ญํ• , ๊ทธ๋ฆฌ๊ณ  ์›น ์„œ๋ฒ„๊ฐ€ RealSubcjet ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.
https://blog.naver.com/hai0416/221629819476

ํ”„๋ก์‹œ ํŒจํ„ด ํŠน์ง•

 

ํŒจํ„ด ์‚ฌ์šฉ ์‹œ๊ธฐ

  • ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๊ฑฐ๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€๋ฐ, ๊ธฐ์กด์˜ ํŠน์ • ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ผ๋•Œ
  • ์ดˆ๊ธฐํ™” ์ง€์—ฐ, ์ ‘๊ทผ ์ œ์–ด, ๋กœ๊น…, ์บ์‹ฑ ๋“ฑ, ๊ธฐ์กด ๊ฐ์ฒด ๋™์ž‘์— ์ˆ˜์ • ์—†์ด ๊ฐ€๋ฏธํ•˜๊ณ  ์‹ถ์„ ๋•Œ

 

ํŒจํ„ด ์žฅ์ 

  • ๊ฐœ๋ฐฉ ํ์‡„ ์›์น™(OCP) ์ค€์ˆ˜
    • ๊ธฐ์กด ๋Œ€์ƒ ๊ฐ์ฒด์˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP) ์ค€์ˆ˜ 
    • ๋Œ€์ƒ ๊ฐ์ฒด๋Š” ์ž์‹ ์˜ ๊ธฐ๋Šฅ์—๋งŒ ์ง‘์ค‘ ํ•˜๊ณ , ๊ทธ ์ด์™ธ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์—ญํ• ์„ ํ”„๋ก์‹œ ๊ฐ์ฒด์— ์œ„์ž„ํ•˜์—ฌ ๋‹ค์ค‘ ์ฑ…์ž„์„ ํšŒํ”ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์›๋ž˜ ํ•˜๋ ค๋˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ๊ทธ์™ธ์˜ ๋ถ€๊ฐ€์ ์ธ ์ž‘์—…(๋กœ๊น…, ์ธ์ฆ, ๋„คํŠธ์›Œํฌ ํ†ต์‹  ๋“ฑ)์„ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ ์œ ์šฉํ•˜๋‹ค
  • ํด๋ผ์ด์–ธํŠธ๋Š” ๊ฐ์ฒด๋ฅผ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ , ์„œ๋น„์Šค ๊ฐ์ฒด๋ฅผ ์ œ์–ดํ•˜๊ฑฐ๋‚˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๋‚˜ ์‹ค์ œ ๊ฐ์ฒด๋‚˜ ์‚ฌ์šฉ๋ฒ•์€ ์œ ์‚ฌํ•˜๋ฏ€๋กœ ์‚ฌ์šฉ์„ฑ์— ๋ฌธ์ œ ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

ํŒจํ„ด ๋‹จ์ 

  • ๋งŽ์€ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ฝ”๋“œ์˜ ๋ณต์žก๋„๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค.
    • ์˜ˆ๋ฅผ๋“ค์–ด ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์— ๋กœ๊น… ๊ธฐ๋Šฅ์„ ๊ฐ€๋ฏธ ์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด, ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ ์ ์šฉํ•จ์—๋„ ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค์— ํ•ด๋‹น๋˜๋Š” ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ ์šฉํ•ด์•ผ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋Ÿ‰์ด ๋งŽ์•„์ง€๊ณ  ์ค‘๋ณต์ด ๋ฐœ์ƒ ๋œ๋‹ค.
    • ์ž๋ฐ”์—์„œ๋Š” ๋ฆฌํ”Œ๋ ‰์…˜์—์„œ ์ œ๊ณตํ•˜๋Š” ๋™์  ํ”„๋ก์‹œ(Dynamic Proxy) ๊ธฐ๋ฒ•์„ ์ด์šฉํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. (ํ›„์ˆ )
  • ํ”„๋ก์‹œ ํด๋ž˜์Šค ์ž์ฒด์— ๋“ค์–ด๊ฐ€๋Š” ์ž์›์ด ๋งŽ๋‹ค๋ฉด ์„œ๋น„์Šค๋กœ๋ถ€ํ„ฐ์˜ ์‘๋‹ต์ด ๋Šฆ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด๋Š” Proxy ํŒจํ„ด

 

๊ฐ€์ƒ ํ”„๋ก์‹œ ํŒจํ„ด ๊ตฌํ˜„ํ•˜๊ธฐ (์ž์› ๊ด€๋ฆฌ)

์ด๋ฏธ์ง€ ๋ทฐ์–ด ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์ด๋ฏธ์ง€ ๋ทฐ์–ด๋Š” ๊ณ ํ•ด์ƒ๋„์˜ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ค€๋‹ค. 

๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌํ•˜๊ณ , showImage() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœํ•˜๋ฉด ํ™”๋ฉด์— ๋ Œ๋”๋ง ํ•˜๋Š” HighREsolutionImage ํด๋ž˜์Šค๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ๋‹ค.

class HighResolutionImage {
    String img;

    HighResolutionImage(String path) {
        loadImage(path);
    }

    private void loadImage(String path) {
        // ์ด๋ฏธ์ง€๋ฅผ ๋””์Šคํฌ์—์„œ ๋ถˆ๋Ÿฌ์™€ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌ (์ž‘์—… ์ž์ฒด๊ฐ€ ๋ฌด๊ฒ๊ณ  ๋งŽ์€ ์ž์›์„ ํ•„์š”๋กœํ•จ)
        try {
            Thread.sleep(1000);
            img = path;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s์— ์žˆ๋Š” ์ด๋ฏธ์ง€ ๋กœ๋”ฉ ์™„๋ฃŒ\n", path);
    }

    @Override
    public void showImage() {
        // ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ๋ Œ๋”๋ง
        System.out.printf("%s ์ด๋ฏธ์ง€ ์ถœ๋ ฅ\n", img);
    }
}

 

ํด๋ฆฐํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ์˜ ์ฝ”๋“œ โŒ

HighREsolutionImage ํด๋ž˜์Šค๋ฅผ ์ด๋ฏธ์ง€ ๋ทฐ์–ด์ธ ImageViewr ํด๋ž˜์Šค์—์„œ ์ด๋ฏธ์ง€ 3๊ฐœ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋กœ๋“œํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

class ImageViewer {
    public static void main(String[] args) {
        HighResolutionImage highResolutionImage1 = new HighResolutionImage("./img/๊ณ ํ•ด์ƒ๋„์ด๋ฏธ์ง€_1");
        HighResolutionImage highResolutionImage2 = new HighResolutionImage("./img/๊ณ ํ•ด์ƒ๋„์ด๋ฏธ์ง€_2");
        HighResolutionImage highResolutionImage3 = new HighResolutionImage("./img/๊ณ ํ•ด์ƒ๋„์ด๋ฏธ์ง€_3");

        highResolutionImage2.showImage();
    }
}

virtual-Proxy-Pattern

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

 

ํ”„๋ก์‹œ ํŒจํ„ด์„ ์ ์šฉํ•œ ์ฝ”๋“œ โœ”๏ธ

์ฆ‰, ํ”„๋ก์‹œ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ์ด๋ฏธ์ง€๋งŒ ๋กœ๋“œํ•ด์„œ ๋ Œ๋”๋งํ•˜๋„๋ก ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ์ œ์–ด๋ฅผ ํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ€์ƒ ํ”„๋ก์‹œ๋ฅผ ์ด์šฉํ•ด  ๋Šฆ์€ ์ดˆ๊ธฐํ™”(Lazy Initialisation)๋กœ ์‹ค์ œ ๊ฐ์ฒด์˜ ์‚ฌ์šฉ ์‹œ์ ์„ ์ œ์–ดํ•ด๋ณด์ž. ์ฐธ๊ณ ๋กœ HighResolutionImage ํด๋ž˜์Šค๊ฐ€ ๋Œ€์ƒ ๊ฐ์ฒด(RealSubject) ๊ฐ€ ๋œ๋‹ค.

ํ”„๋ก์‹œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์žˆ์–ด ๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผํ•  ์ผ์€, ๋Œ€์ƒ ๊ฐ์ฒด์™€ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์ฃผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋‹คํ˜•์„ฑ์„ ์ด์šฉํ•ด ๋Œ€์ƒ, ํ”„๋ก์‹œ ๊ฐ์ฒด ๋ชจ๋‘๋ฅผ ํ•˜๋‚˜์˜ ํƒ€์ž…์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด์„œ๋‹ค.

virtual-Proxy-Pattern

// ๋Œ€์ƒ ๊ฐ์ฒด์™€ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋ฌถ๋Š” ์ธํ„ฐํŽ˜์ด์Šค (๋‹คํ˜•์„ฑ)
interface IImage {
    void showImage(); // ์ด๋ฏธ์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„์ฒด๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ถ”์ƒ๋ฉ”์†Œ๋“œ
}
// ๋Œ€์ƒ ๊ฐ์ฒด (RealSubject)
class HighResolutionImage implements IImage {
    String img;

    HighResolutionImage(String path) {
        loadImage(path);
    }

    private void loadImage(String path) {
        // ์ด๋ฏธ์ง€๋ฅผ ๋””์Šคํฌ์—์„œ ๋ถˆ๋Ÿฌ์™€ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌ (์ž‘์—… ์ž์ฒด๊ฐ€ ๋ฌด๊ฒ๊ณ  ๋งŽ์€ ์ž์›์„ ํ•„์š”๋กœํ•จ)
        try {
            Thread.sleep(1000);
            img = path;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s์— ์žˆ๋Š” ์ด๋ฏธ์ง€ ๋กœ๋”ฉ ์™„๋ฃŒ\n", path);
    }

    @Override
    public void showImage() {
        // ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ๋ Œ๋”๋ง
        System.out.printf("%s ์ด๋ฏธ์ง€ ์ถœ๋ ฅ\n", img);
    }
}
// ํ”„๋ก์‹œ ๊ฐ์ฒด (Proxy)
class ImageProxy implements IImage {
    private IImage proxyImage;
    private String path;

    ImageProxy(String path) {
        this.path = path;
    }

    @Override
    public void showImage() {
        // ๊ณ ํ•ด์ƒ๋„ ์ด๋ฏธ์ง€ ๋กœ๋”ฉํ•˜๊ธฐ
        proxyImage = new HighResolutionImage(path);
        proxyImage.showImage();
    }
}
class ImageViewer {
    public static void main(String[] args) {
        IImage highResolutionImage1 = new ImageProxy("./img/๊ณ ํ•ด์ƒ๋„์ด๋ฏธ์ง€_1");
        IImage highResolutionImage2 = new ImageProxy("./img/๊ณ ํ•ด์ƒ๋„์ด๋ฏธ์ง€_2");
        IImage highResolutionImage3 = new ImageProxy("./img/๊ณ ํ•ด์ƒ๋„์ด๋ฏธ์ง€_3");

        highResolutionImage2.showImage();
    }
}

virtual-Proxy-Pattern

์ด๋ฏธ์ง€ ๋ทฐ์–ด ํด๋ž˜์Šค(ํด๋ผ์ด์–ธํŠธ)์˜ ์ฝ”๋“œ ์ž์ฒด๋Š” ํฌ๊ฒŒ ๋ณ€ํ•˜์ง€ ์•Š์•˜๋‹ค. ๋˜‘๊ฐ™์ด ์ด๋ฏธ์ง€ 3๊ฐœ๋ฅผ ๋กœ๋“œํ•˜๋Š” ์ฝ”๋“œ์ธ๋ฐ, ๋Œ€์ƒ ๊ฐ์ฒด ๋Œ€์‹ ์— ํ”„๋ก์‹œ ๊ฐ์ฒด์— ํ• ๋‹นํ•œ ์ ์ด ๋‹ค๋ฅผ ๋ฟ์ด๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด๋ถ€ ๋™์ž‘ ๋ฐฉ์‹์€ ํฌ๊ฒŒ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”๋ฐ, ํ”„๋ก์‹œ ๊ฐ์ฒด ๋‚ด์—์„œ ๊ฒฝ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€๋‹ˆ๊ณ  ์žˆ๋‹ค๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ showImage๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ทธ๋•Œ์„œ์•ผ ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ๋กœ๋“œ(lazyload)ํ•˜์—ฌ, ์ด๋ฏธ์ง€๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌํ•˜๊ณ  ๋Œ€์ƒ ๊ฐ์ฒด์˜ showIMage() ๋ฉ”์„œ๋“œ๋ฅผ ์œ„์ž„ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ, ์‹ค์ œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์— ๋ฉ”๋ชจ๋ฆฌ ์ ์žฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”ํ•œ ์ž์›๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๋‹ค.


๋ณดํ˜ธ ํ”„๋ก์‹œ ํŒจํ„ด ๊ตฌํ˜„ํ•˜๊ธฐ

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

 

๊ธฐ์กด ํ”„๋กœ๊ทธ๋žจ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค. ๋จผ์ € ํšŒ์‚ฌ์˜ ์ง์ฑ…์„ ํ‘œํ˜„ํ•˜๋Š” RESPONSIBILITY enum ์ƒ์ˆ˜ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค. ์ฐจ๋ก€๋Œ€๋กœ ์‚ฌ์›(Staff), ๊ณผ์žฅ(Manager), ์ƒ๋ฌด(Director) ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ƒ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

// ์ง์ฑ… ์ƒ์ˆ˜
enum RESPONSIBILITY {
    STAFF, // ์‚ฌ์›
    MANAGER, // ๊ณผ์žฅ
    DIRECTOR // ์ƒ๋ฌด
}

๊ทธ๋ฆฌ๊ณ  ์ง์›์˜ ์ •๋ณด๋ฅผ ํด๋ž˜์Šคํ™”ํ•œ Employee ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค. ์ด ํด๋ž˜์Šค์—๋Š” ๊ตฌ์„ฑ์›์˜ ์ด๋ฆ„๊ณผ ์ง์ฑ…์˜ ์ •๋ณด๋ฅผ ํ•œ๋ฒˆ์— ์•Œ์ˆ˜ ์žˆ๋Š” getInfo() ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

// ๊ตฌ์„ฑ์› ํด๋ž˜์Šค
class Employee {
    private String name; // ์ด๋ฆ„
    private RESPONSIBILITY position; // ์ง์œ„

    public Employee(String name, RESPONSIBILITY position) {
        this.name = name;
        this.position = position;
    }

    public String getName() {
        return name;
    }

    public RESPONSIBILITY getGrade() {
        return position;
    }

    public String getInfo(Employee viewer) {
        return "Display " + getGrade().name() + " '" + getName() + "' personnel information.";
    }
}

๋งˆ์ง€๋ง‰์œผ๋กœ ํšŒ์‚ฌ์˜ ์ „ ๊ตฌ์„ฑ์›์„ ๋ชจ๋‘ ์ถœ๋ ฅํ•˜๋Š” PrintEmployeeInfo ํด๋ž˜์Šค ํ”„๋กœ๊ทธ๋žจ์ด ์žˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ์ƒ์„ฑ์ž์˜ ์ธ์ž๋กœ ๋ˆ„๊ฐ€ ์กฐํšŒํ•˜๋Š”์ง€ ๋Œ€์ƒ์ž(viewer)๋ฅผ ๋ฐ›๊ณ  ๋ชจ๋“  ๊ตฌ์„ฑ์› ๋ฆฌ์ŠคํŠธ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ์ถœ๋ ฅํ•ด์ฃผ๋Š” printAllInfo() ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

class PrintEmployeeInfo {
    Employee viewer; // ์กฐํšŒํ•˜๋ ค๋Š” ์ž
    
    PrintEmployeeInfo(Employee viewer) {
        this.viewer = viewer;
    }
	
    // Employee ๊ฐ์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ›์•„ ์ง์›๋“ค์˜ ์ •๋ณด๋ฅผ ์ˆœํšŒํ•˜์—ฌ ์กฐํšŒ
    void printAllInfo(List<Employee> employees) {
        employees.stream()
                .map(employee -> employee.getInfo(viewer))
                .forEach(System.out::println);
    }
}

 

ํด๋ฆฐํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ์˜ ์ฝ”๋“œ โŒ

์ง์ฑ…์— ๋Œ€ํ•œ ํด๋ž˜์Šค ๊ตฌ์„ฑ ์ž์ฒด๋Š” ํฐ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ง€๊ธˆ ์ด ์ƒํƒœ๋กœ๋งŒ ๋†”๋‘”๋‹ค๋ฉด ์–ด๋Š ๋ˆ„๊ตฌ๋“ ์ง€ PrintEmployeeInfo ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด printAllInfo() ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ชจ๋“  ์ง์›์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณผ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

public static void main(String[] args) {
    // ์ง์›๋ณ„ ๊ฐœ์ธ ๊ฐ์ฒด ์ƒ์„ฑ
    Employee CTO = new Employee("Dragon Jung", RESPONSIBILITY.DIRECTOR);
    Employee devManager = new Employee("Cats Chang", RESPONSIBILITY.MANAGER);
    Employee financeManager = new Employee("Dell Choi", RESPONSIBILITY.MANAGER);
    Employee devStaff = new Employee("Dark Kim", RESPONSIBILITY.STAFF);
    Employee financeStaff = new Employee("Pal Yoo", RESPONSIBILITY.STAFF);

    // ์ง์›๋“ค์„ ๋ฆฌ์ŠคํŠธ๋กœ ๊ฐ€๊ณต
    List<Employee> employees = Arrays.asList(CTO, devManager, financeManager, devStaff, financeStaff);

    /*-----------------------------------------------------------------------------------------*/

    // ๋‚˜ : ์ผ๊ฐœ ์‚ฌ์› ์ง์ฑ…
    Employee me = new Employee("inpa", RESPONSIBILITY.STAFF);

    System.out.println("\n================================================================");
    System.out.println("์‹œ๋‚˜๋ฆฌ์˜ค1. ์ผ๊ฐœ ์‚ฌ์›์ธ ๋‚ด๊ฐ€ ํšŒ์‚ฌ ์ธ์› ์ธ์‚ฌ ์ •๋ณด ์กฐํšŒ");
    System.out.println("================================================================");
    PrintEmployeeInfo view = new PrintEmployeeInfo(me); // ๋ชจ๋“  ์ง์› ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ํด๋ž˜์Šค
    view.printAllInfo(employees); // ์ผ๊ฐœ ์‚ฌ์›์— ๋ถˆ๊ตฌํ•˜๊ณ  ๋ชจ๋“  ์ง์› ์กฐํšŒ
}

protection-Proxy-Pattern

๋”ฐ๋ผ์„œ ์ง์œ„์— ๋”ฐ๋ผ ์ •๋ณด ์—ด๋žŒ ์ ‘๊ทผ ์ œํ•œ์„ ๋‘์–ด์•ผ ๋˜๋Š”๋ฐ, ๊ธฐ์กด์˜ ํ”„๋กœ๊ทธ๋žจ์„ ์ˆ˜์ •ํ•˜๊ธฐ์—” ๋น„์šฉ์ด ๋งŽ์ด ๋“ ๋‹ค๊ณ  ํ•œ๋‹ค. ์ด๋Ÿด๋•Œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๊ธฐ์กด์˜ ํ”„๋กœ๊ทธ๋žจ์˜ ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ์ œ์–ดํ•˜๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค.

 

ํ”„๋ก์‹œ ํŒจํ„ด์„ ์ ์šฉํ•œ ์ฝ”๋“œ โœ”๏ธ

๋ณดํ˜ธ ํ”„๋ก์‹œ๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์‹ค์ œ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•œ๋‹ค. ์—ฌ๊ธฐ์„  ์ง์ฑ…์— ๋”ฐ๋ฅธ ์ •๋ณด ์—ด๋žŒ ์ ‘๊ทผ ์ œ์–ด์ด๋‹ค.

์—ฌ๋Ÿฌ๋ฒˆ ๋งํ–ˆ๋“ฏ์ด ํ”„๋ก์‹œ๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ์— ์•ž์„œ, ์šฐ์„  ๋Œ€์ƒ ๊ฐ์ฒด์™€ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋ชจ๋‘ ๋ฌถ์–ด์ฃผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ ์–ธํ•ด์ค€๋‹ค.

// ๊ตฌ์„ฑ์› ์ธํ„ฐํŽ˜์ด์Šค
interface IEmployee {
    String getName(); // ๊ตฌ์„ฑ์›์˜ ์ด๋ฆ„
    RESPONSIBILITY getGrade(); // ๊ตฌ์„ฑ์›์˜ ์ง์ฑ…
    String getInfo(IEmployee viewer); // ๊ตฌ์„ฑ์›์˜ ์ธ์‚ฌ์ •๋ณด
}

๊ทธ๋ฆฌ๊ณ  ์ด๋•Œ๊นŒ์ง€ Employee ํด๋ž˜์Šค ํƒ€์ž…์œผ๋กœ ๋ฐ›์€ ๋ชจ๋“  ๋ณ€์ˆ˜์™€ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์žฌ์„ค์ •ํ•ด์ค€๋‹ค.

protection-Proxy-Pattern
protection-Proxy-Pattern

์ด์ œ ๋ณธ๊ฒฉ์ ์ธ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ์„ค์ •ํ•  ์ฐจ๋ก€์ด๋‹ค. ๊ทธ๋™์•ˆ ๋ฌด์ง€์„ฑ์œผ๋กœ ๋ชจ๋“  ๊ตฌ์„ฑ์›์„ ์ถœ๋ ฅํ•ด์ฃผ๋˜ ๋Œ€์ƒ ๊ฐ์ฒด์˜ getInfo() ๋ฉ”์„œ๋“œ๋ฅผ ์ œ์–ด ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๋Œ€์ƒ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์œ„์ž„ ํ˜ธ์ถœํ•ด์คŒ์œผ๋กœ์จ ๋ณดํ˜ธ ํ”„๋ก์‹œ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

// ๋ณดํ˜ธ ํ”„๋ก์‹œ : ์ธ์‚ฌ์ •๋ณด๊ฐ€ ๋ณดํ˜ธ๋œ ๊ตฌ์„ฑ์› (์ธ์‚ฌ ์ •๋ณด ์—ด๋žŒ ๊ถŒํ•œ ์—†์œผ๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ)
class ProtectedEmployee implements IEmployee {
    private IEmployee employee;

    public ProtectedEmployee(IEmployee employee) {
        this.employee = employee;
    }

    @Override
    public String getInfo(IEmployee viewer) {

        RESPONSIBILITY position = this.employee.getGrade(); // ์กฐํšŒ ๋‹นํ•˜๋Š” ์ž์˜ ์ง์ฑ…์„ ์–ป๊ธฐ
		
        // ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ์กฐํšŒ์ž์˜ ์ง์ฑ…์— ๋”ฐ๋ผ ์ถœ๋ ฅ์„ ์ œ์–ด
        switch (viewer.getGrade()) {
            case DIRECTOR:
                // ๋ถ€์‚ฌ์žฅ์€ ๊ณผ์žฅ, ์‚ฌ์›๋“ค์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
                return this.employee.getInfo(viewer);
            case MANAGER:
                // ๊ณผ์žฅ์€ ๊ฐ™์€ ์ง๋ฌด์™€ ๊ทธ ์•„๋ž˜ ์‚ฌ์›๋“ค์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์žฅ ์ •๋ณด๋Š” ๋ณผ ์ˆ˜ ์—†๋‹ค.
                if (position != RESPONSIBILITY.DIRECTOR) {
                    return this.employee.getInfo(viewer);
                }
            case STAFF:
                // ์‚ฌ์›์€ ๊ฐ™์€ ์ง๋ฌด์ธ ์‚ฌ๋žŒ๋“ค๋งŒ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ณผ์žฅ, ์‚ฌ์žฅ ์ •๋ณด๋Š” ๋ณผ ์ˆ˜ ์—†๋‹ค.
                if (position != RESPONSIBILITY.DIRECTOR && position != RESPONSIBILITY.MANAGER) {
                    return this.employee.getInfo(viewer);
                }
            default: return "๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์ธ์‚ฌ์ •๋ณด๋ฅผ ์กฐํšŒ ํ• ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค";
        }
    }

    @Override
    public String getName() {
        return employee.getName();
    }

    @Override
    public RESPONSIBILITY getGrade() {
        return employee.getGrade();
    }
}

์ด์ œ ๊ธฐ์กด ํ”„๋กœ๊ทธ๋žจ์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” employees ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์™€ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ์„œ(wrap) ํ”„๋ก์‹œ๋กœ ์ธ์Šคํ„ด์Šคํ™” ํ•ด์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ”„๋ก์‹œ๋กœ ์žฌ๊ตฌ์„ฑ๋œ ๋ฆฌ์ŠคํŠธ List<IEmployee> protectedEmployees๋ฅผ PrintEmployeeInfo ๊ฐ์ฒด์˜ printAllInfo() ๋ฉ”์„œ๋“œ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๊ฒŒ๋˜๋ฉด, getInfo() ํ•˜๋Š” ๊ณผ์ •์—์„œ ํ”„๋ก์‹œ์˜ switch ๋กœ์ง์— ๊ฑธ๋ฆฌ๊ฒŒ ๋˜์–ด ์กฐํšŒ์ž์— ๊ถŒํ•œ์ด ์—†๋‹ค๋ฉด ๊ฒฝ๊ณ  ๋ฌธ๊ตฌ๋ฅผ ๋ณด๋‚ด์ฃผ๊ฒŒ ๋œ๋‹ค.

protection-Proxy-Pattern

class Client {
    public static void main(String[] args) {
        // ์ง์›๋ณ„ ๊ฐœ์ธ ๊ฐ์ฒด ์ƒ์„ฑ
        Employee CTO = new Employee("Dragon Jung", RESPONSIBILITY.DIRECTOR);
        Employee devManager = new Employee("Cats Chang", RESPONSIBILITY.MANAGER);
        Employee financeManager = new Employee("Dell Choi", RESPONSIBILITY.MANAGER);
        Employee devStaff = new Employee("Dark Kim", RESPONSIBILITY.STAFF);
        Employee financeStaff = new Employee("Pal Yoo", RESPONSIBILITY.STAFF);

        // ์ง์›๋“ค์„ ๋ฆฌ์ŠคํŠธ๋กœ ๊ฐ€๊ณต
        List<Employee> employees = Arrays.asList(CTO, devManager, financeManager, devStaff, financeStaff);

        /*-----------------------------------------------------------------------------------------*/

        // ๊ธฐ์กด์— ๋“ฑ๋ก๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์œผ๋‹ˆ, ๋™์ ์œผ๋กœ ๊ธฐ์กด์˜ Employee ๊ฐ์ฒด๋ฅผ ํ”„๋ก์‹œ ๊ฐ์ฒด ProtectedEmployee๋กœ Wrapํ•˜๋Š” ์ž‘์—…์„ ์‹คํ–‰ํ•œ๋‹ค.
        List<IEmployee> protectedEmployees = new ArrayList<>();
        for (Employee e : employees) {
            protectedEmployees.add(new ProtectedEmployee((IEmployee) e));
        }

        /*-----------------------------------------------------------------------------------------*/

        // ๋‚˜ : ์ผ๊ฐœ ์‚ฌ์› ์ง์ฑ…
        Employee me = new Employee("inpa", RESPONSIBILITY.STAFF);

        System.out.println("\n================================================================");
        System.out.println("์‹œ๋‚˜๋ฆฌ์˜ค1. ์ผ๊ฐœ ์‚ฌ์›์ธ ๋‚ด๊ฐ€ ํšŒ์‚ฌ ์ธ์› ์ธ์‚ฌ ์ •๋ณด ์กฐํšŒ");
        System.out.println("================================================================");
        PrintEmployeeInfo view = new PrintEmployeeInfo(me); 
        view.printAllInfo(protectedEmployees); 

        System.out.println("\n================================================================");
        System.out.println("์‹œ๋‚˜๋ฆฌ์˜ค2. ๊ณผ์žฅ์ด ํšŒ์‚ฌ ์ธ์› ์ธ์‚ฌ ์ •๋ณด ์กฐํšŒ");
        System.out.println("================================================================");
        PrintEmployeeInfo view2 = new PrintEmployeeInfo(devManager);
        view2.printAllInfo(protectedEmployees); 

        System.out.println("\n================================================================");
        System.out.println("์‹œ๋‚˜๋ฆฌ์˜ค3. ์ƒ๋ฌด๊ฐ€ ํšŒ์‚ฌ ์ธ์› ์ธ์‚ฌ ์ •๋ณด ์กฐํšŒ");
        System.out.println("================================================================");
        PrintEmployeeInfo view3 = new PrintEmployeeInfo(CTO);
        view3.printAllInfo(protectedEmployees);
    }
}

protection-Proxy-Pattern


์‹ค๋ฌด์—์„œ ์ฐพ์•„๋ณด๋Š” Proxy ํŒจํ„ด

 

Java

  • java.lang.reflect.Proxy
  • java.rmi.* (์›๊ฒฉ ํ”„๋ก์‹œ ๋ชจ๋“ˆ)
  • javax.ejb.EJB 
  • javax.inject.Inject
  • javax.persistence.PersistenceContext

 

Dynamic Proxy

๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋””์ž์ธ ํŒจํ„ด์œผ๋กœ์„œ ํ”„๋ก์‹œ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•ด๋„ ๋˜์ง€๋งŒ, ์ž๋ฐ” JDK์—์„œ๋Š” ๋ณ„๋„๋กœ ํ”„๋ก์‹œ ๊ฐ์ฒด ๊ตฌํ˜„ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค. ์ด๋ฅผ ๋™์  ํ”„๋ก์‹œ(Dynamic Proxy) ๊ธฐ๋ฒ•์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ์šด๋‹ค.

๋™์  ํ”„๋ก์‹œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ผ์ผํžˆ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ๋„์ค‘ java.lang.reflect.Proxy ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” API๋ฅผ ์ด์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ ํ”„๋ก์‹œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ์„œ, ์ž๋ฐ”์˜ Reflection API ๊ธฐ๋ฒ•์„ ์‘์šฉํ•œ ์—ฐ์žฅ์„ ์˜ ๊ฐœ๋…์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋ณ„๋„์˜ ํ”„๋ก์‹œ ํด๋ž˜์Šค ์ •์˜์—†์ด ๋Ÿฐํƒ€์ž„์œผ๋กœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ด ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

[JAVA] โ˜• ๋ˆ„๊ตฌ๋‚˜ ์‰ฝ๊ฒŒ ๋ฐฐ์šฐ๋Š” Dynamic Proxy ๋‹ค๋ฃจ๊ธฐ

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

inpa.tistory.com

// ๋Œ€์ƒ ๊ฐ์ฒด์™€ ํ”„๋ก์‹œ๋ฅผ ๋ฌถ๋Š” ์ธํ„ฐํŽ˜์ด์Šค
interface Animal {
    void eat();
}

// ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•  ํƒ€๊ฒŸ ๊ฐ์ฒด
class Tiger implements Animal{
    @Override
    public void eat() {
        System.out.println("ํ˜ธ๋ž‘์ด๊ฐ€ ์Œ์‹์„ ๋จน์Šต๋‹ˆ๋‹ค.");
    }
}
public class Client {
    public static void main(String[] arguments) {
		
        // newProxyInstance() ๋ฉ”์„œ๋“œ๋กœ ๋™์ ์œผ๋กœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
        Animal tigerProxy = (Animal) Proxy.newProxyInstance(
                Animal.class.getClassLoader(), // ๋Œ€์ƒ ๊ฐ์ฒด์˜ ์ธํ„ฐํŽ˜์ด์Šค์˜ ํด๋ž˜์Šค๋กœ๋”
                new Class[]{Animal.class}, // ๋Œ€์ƒ ๊ฐ์ฒด์˜ ์ธํ„ฐํŽ˜์ด์Šค
                new InvocationHandler() { // ํ”„๋ก์‹œ ํ•ธ๋“ค๋Ÿฌ
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object target = new Tiger();

                        System.out.println("----eat ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „----");

                        Object result = method.invoke(target, args); // ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ

                        System.out.println("----eat ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํ›„----");

                        return result;
                    }
                }
        );

        tigerProxy.eat();
    }
}

Dynamic Proxy


Spring Framework

 

์Šคํ”„๋ง AOP

์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํ”„๋ก์‹œ ๊ธฐ์ˆ ์„ ์ •๋ง ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. (AOP, JPA ๋“ฑ)

์Šคํ”„๋ง์—์„œ๋Š” Bean์„ ๋“ฑ๋กํ•  ๋•Œ Singleton์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Dynamic Proxy ๊ธฐ๋ฒ•์„ ์ด์šฉํ•ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ Bean์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค. ๋˜ํ•œ Bean์œผ๋กœ ๋“ฑ๋กํ•˜๋ ค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ์ฒด๊ฐ€ Interface๋ฅผ ํ•˜๋‚˜๋ผ๋„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์œผ๋ฉด JDK๋ฅผ ์ด์šฉํ•˜๊ณ  Interface๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฉด ๋‚ด์žฅ๋œ CGLIB ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ๋‹ค.

@Service
public class GameService {
	public void startDame() {
    	System.out.println("์ด ์ž๋ฆฌ์— ์˜ค์‹  ์—ฌ๋Ÿฌ๋ถ„์„ ์ง„์‹ฌ์œผ๋กœ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.");
    }
}
@Aspect
@Comonent
public class PerfAspect {
	@Around("bean(gameService)")
	public void timestamp(ProceedingJoinPoint point) throws Throwable {
    	System.out.println("ํ”„๋ก์‹œ ์‹คํ–‰ 1");
        
        point.proceed(); // ๋Œ€์ƒ ๊ฐ์ฒด์˜ ์›๋ณธ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰
        
        System.out.println("ํ”„๋ก์‹œ ์‹คํ–‰ 2");
    }
}

JavaScript

 

Proxy / Reflect ๊ฐ์ฒด

์ž๋ฐ”์—์„œ๋„ Proxy ๊ฐ์ฒด๋ฅผ ๋ณ„๋„๋กœ ์ง€์›ํ•˜๋“ฏ์ด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ง„์˜์—์„œ๋„ ๋…๋ฆฝ์ ์ธ Proxy ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ์˜ Proxy ๊ฐ์ฒด์˜ ์—ญํ• ์€ ๋Œ€์ƒ ๊ฐ์ฒด์„ ๊ฐ์‹ธ์„œ(wrapping), ์†์„ฑ ์กฐํšŒ, ํ• ๋‹น, ์—ด๊ฑฐ ๋ฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋“ฑ ์—ฌ๋Ÿฌ ๊ธฐ๋ณธ ๋™์ž‘์„ ๊ฐ€๋กœ์ฑ„(trap) ํŠน๋ณ„ํ•œ ๋‹ค๋ฅธ ๋™์ž‘์„ ๊ฐ€๋ฏธ์‹œํ‚ค๋Š” ๋Œ€๋ฆฌ์ž ์—ญํ• ์„ ํ•œ๋‹ค. ๋Œ€์ƒ ๊ฐ์ฒด๋Š” Object, Array ๋“ฑ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“  ์ž๋ฃŒํ˜•์ด ๋Œ€์ƒ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

 

[JS] ๐Ÿ“š ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Proxy & Reflect ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•

JavaScript Proxy ๊ฐ์ฒด ํ”„๋ก์‹œ(Proxy)์˜ ์‚ฌ์ „์  ๋œป์€ '๋Œ€๋ฆฌ์ธ', '๋Œ€๋ฆฌ'๋ผ๋Š” ๋œป์ด๋‹ค. ์„œ๋ฒ„๋ฅผ ๋‹ค๋ค„๋ณธ ๋…์ž๋ถ„๋“ค์ด๋ผ๋ฉด ํ”„๋ก์‹œ ์„œ๋ฒ„์— ๋Œ€ํ•ด ์งˆ๋ฆฌ๋„๋ก ๋“ค์–ด๋ดค์„ ๊ฒƒ์ด๋‹ค. ํ”„๋ก์‹œ ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ๋ณธ ์„œ๋ฒ„

inpa.tistory.com

let obj = {
    name: 'ํ™๊ธธ๋™',
    print: function () {
        console.log(`My Name is ${this.name}`);
    },
};

// print ํ•จ์ˆ˜๋ฅผ ํ”„๋ก์‹œ๋กœ ๊ฐ์‹ธ๊ธฐ
obj.print = new Proxy(obj.print, {
    apply(target, thisArg, args) {
        console.log('๋ฉ”์„œ๋“œ ์‹คํ–‰ํ•  ๋•Œ ์ค‘๊ฐ„์— ๊ฐ€๋กœ์ฑ„์–ด ๋กœ์ง ์‹œํ–‰');

        console.log('target: ', target); // ๋Œ€์ƒ ํ•จ์ˆ˜
        console.log('thisArg: ', thisArg); // this์˜ ๊ฐ’
        console.log('args: ', args); // ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก (๋ฐฐ์—ด)

        console.log('์ด๋ฆ„ ๋ฐ”๊ฟ” ๋ฒ„๋ฆฌ๊ธฐ ~');
        thisArg.name = '์ž„๊บฝ์ •';

        Reflect.apply(target, thisArg, args); // ๋Œ€์ƒ ์›๋ณธ ํ•จ์ˆ˜ ์‹คํ–‰
    },
});

obj.print();

javascript-Proxy-Reflect


# ์ฐธ๊ณ ์ž๋ฃŒ

์ฝ”๋”ฉ์œผ๋กœ ํ•™์Šตํ•˜๋Š” GoF์˜ ๋””์ž์ธ ํŒจํ„ด - ๋ฐฑ๊ธฐ์„ 

https://refactoring.guru/design-patterns/proxy

https://effectiveprogramming.tistory.com/entry/Proxy-%ED%8C%A8%ED%84%B4%EA%B3%BC-%EA%B7%B8-%ED%99%9C%EC%9A%A9

https://www.oodesign.com/proxy-pattern

https://jdm.kr/blog/235