본문 바로가기
기타/자바 디자인패턴

[자바 디자인패턴] 4. Proxy 패턴

by 창이2 2023. 2. 12.

이번 포스팅은 프록시 패턴에 대해 적어보고자 합니다.

Proxy 라는 뜻은 대리인이라는 의미를 갖는데, 자바에서 프록시 패턴은

대리인을 통해 일을 처리하는 패턴을 의미합니다.

 

Printer 기능에 대해 프록시패턴을 적용했을때 아래와 같이 3개의 파일이 필요합니다.

 

Printer Printer 기능을 하는 클래스
PrinterInterface Printer와 PrinterProxy의 공통 인터페이트
PrinterProxy Printer를 갖고 있으면서 대리인의 기능을 하는 클래스

Printer기능을 이용할때 Printer를 직접 이용하는 것이 아니라 PrinterProxy(대리인)를 통해 그 기능을 수행하게 됩니다.

 

Proxy패턴을 사용하는 이유는 크게 3가지 이유가 있습니다.

 

1. SOLID 원칭중 OCP 원칙을 지킬 수 있다. (기존의 구조는 유지하면서 새로운 기능 확장에는 유연)

2.SOLID 원칭중 SRP 원칙을 지킬 수 있다.  

3.객체의 초기화 시점을 Lazy하게 구성할 수 있다.

 

단점이라 하면 로직이 단일 객체로 사용할때 보다 조금 더 복잡해지고 객체 생성시 한 단계더 거치기 때문에 빈번하게 생성이 필요한 경우에성능저하가 일어날 수 있습니다. 

 

아래는 예제 코드입니다.

 

class Printer : PrinterInterface {
    private var name: String

    constructor() {
        this.name = ""
        println("Printer의 인스턴스를 생성 중")
    }

    constructor(name: String) {
        this.name = name
        println("Printer의 인스턴스 (${name})을 생성 중")
    }

    private fun dpHeavyJob(name: String) {
        print("$name")
        for (i in 0 until 5) {
            try {
                Thread.sleep(1000)
            } catch (e: Exception) {
            }
            print(".")
        }
        println("완료.")
    }

    override fun setPrinterName(name: String) {
        this.name = name
    }

    override fun getPrinterName(): String {
        return name
    }

    override fun print(name: String) {
        println("===name===")
        println(name)
    }
}

// Printer의 대리 클래스
class PrinterProxy : PrinterInterface {
    private var name: String = ""
    private lateinit var realPrinter: Printer // 실제 프린터

    constructor(name: String) {
        this.name = name
    }

    override fun setPrinterName(name: String) {
        if (this::realPrinter.isInitialized) {
            realPrinter.setPrinterName(name = name)
        }
        this.name = name
    }

    override fun getPrinterName(): String {
        return name
    }

    override fun print(name: String) {
        realize()
        realPrinter.print(name)
    }

    private fun realize() {
        if (this::realPrinter.isInitialized.not()) {
            realPrinter = Printer(name = name)
        }
    }
}

interface PrinterInterface {
    fun setPrinterName(name: String)
    fun getPrinterName(): String
    fun print(name: String)
}

fun main() {
    val printer: PrinterInterface = PrinterProxy(name = "ChangGyu")
    println("현재 이름은 ${printer.getPrinterName()} 입니다.")
    printer.setPrinterName("Charles Lee")
    println("현재 이름은 ${printer.getPrinterName()} 입니다.")
    println("완료.")
}

 

참고 : 자바언어로 배우는 디자인패턴 입문

댓글