데코레이터 패턴 🎁

표지 사진 by Silvio Kundt on Unsplash

Decorator 패턴은 인터페이스를 변경하지 않고 주어진 객체의 기능을 향상시켜야 할 때 사용되는 구조적 디자인 패턴입니다.

이 패턴에서는 일반적으로 특정 인터페이스를 구현하는 기본/베어본 클래스가 있습니다. 이와 함께 사용자가 인터페이스를 변경하지 않고 기본 클래스의 메서드를 향상시킬 수 있는 여러 "래퍼"클래스가 있습니다.

이는 "Wrapper"클래스도 동일한 인터페이스를 구현함을 의미합니다.

이것을 더 잘 이해하기 위해 예를 들어보겠습니다. 사용자 정보를 스토리지 시스템에 저장해야 하는 사용 사례와 저장하기 전에 일부 데이터를 암호화해야 할 때 어떤 일이 발생하는지 논의할 것입니다. 🗃

스토리지 시스템



사용자 데이터를 저장하는 웹사이트 잠재고객용 스토리지 시스템이 있다고 가정합니다. 이 경우에는 email 입니다. 훌륭한 개발자는 이 모듈을 매우 일반적으로 설계했으며 현재 조직의 여러 팀에서 사용하고 있습니다. 😎

모든 것이 훌륭하게 들립니까? 여기 문제가 있습니다. 새로운 요구 사항이 있습니다. 팀만 사용자 데이터를 저장하기 전에 암호화하면 됩니다. 🤯

분명히 기존 모듈을 수정할 수 없습니다. 너무 많은 팀이 사용 중이며 사용하면 🙃 당신을 죽일 것입니다. 또한 모든 것을 처음부터 다시 작성할 수 없습니다. 당신은 그것을 위한 충분한 시간이 없으며 또한 이것을 해결하는 가장 좋은 방법이 아닙니다.

동료가 데코레이터 패턴에 대해 말한 것을 기억하고 이를 실행에 옮기기로 결정했습니다 💡. 진행 방법은 다음과 같습니다.
  • StorageSystemwriteInfo 두 가지 메서드가 포함된 readInfo 인터페이스가 있습니다.
  • StorageSystem를 구현하여 이전에 생성한 구조체는 GenericStorageSystem입니다. - 이것은 단지 정보를 메모리에 저장한다고 가정합니다.
  • 요구 사항을 충족하려면 데이터를 암호화하는 동시에 구현할 일부 구조체가 필요합니다StorageSystem. 예, 반복합니다. 처음부터 새 구조체를 만들 수는 없습니다. GenericStorageSystem 를 사용해야 합니다.
  • 생성하기로 결정했습니다. EncryptedStorageSystem . GenericStorageSystem를 감싸고 데이터를 암호화/복호화한 후 writeInforeadInfowriteInfo를 각각 호출하는 readInfoGenericStorageSystem를 구현합니다.

  • 짜잔! 많은 시간을 절약하고 확장 가능한 솔루션을 갖게 되었습니다. 여기, 당신의 노력에 대한 쿠키가 있습니다 🍪

    Go 코드에서 이것이 어떻게 보이는지 봅시다.

    type StorageSystem interface {
        writeInfo(info string)
        readInfo() string
    }
    
    type GenericStorageSystem struct {
        info string
    }
    
    func (g *GenericStorageSystem) writeInfo(info string) {
        // write information to file system as is.
        fmt.Println("Writing info to the file system: ", info)
        g.info = info
    }
    
    func (g *GenericStorageSystem) readInfo() string {
        // Return info from file system as is.
        fmt.Println("Reading info from the file system: ", g.info)
        return g.info
    }
    



    type EncryptedStorageSystem struct {
        storageSystem StorageSystem
    }
    
    func (e *EncryptedStorageSystem) writeInfo(info string) {
        fmt.Println("Encrypting the data")
        encryptedInfo := encrypt(info)
        e.storageSystem.writeInfo(encryptedInfo)
    }
    
    func (e *EncryptedStorageSystem) readInfo() string {
        info := e.storageSystem.readInfo()
        decryptedInfo := decrypt(info)
        fmt.Println("Decrypting info from the file system: ", decryptedInfo)
        return decryptedInfo
    }
    

    더미encryptdecrypt 함수도 만들어 보겠습니다. 이것들은 문자열을 다른 방향으로 회전시킵니다.

    func encrypt (info string) string {
        return info[1:len(info)] + string(info[0])
    }
    
    
    func decrypt (info string) string {
        return string(info[len(info) - 1]) + info[0:len(info)-1]
    }
    

    💃🏻💃🏻. 실제로 확인해 보겠습니다.

    func main() {
        info := "[email protected]"
        genericStorage := GenericStorageSystem{}
    
        genericStorage.writeInfo(info)
        genericStorage.readInfo()
    
        fmt.Println("------------")
    
        encryptedStorage = EncryptedStorage{
            storageSystem: genericStorage,
        }
    
        encryptedStorage.writeInfo(info)
        encryptedStorage.readInfo()
    }
    

    출력에서 다음을 확인해야 합니다.

    Writing info to the file system:  [email protected]
    Reading info from the file system:  [email protected]
    ------------
    Encrypting the data
    Writing info to the file system:  [email protected]
    Reading info from the file system:  [email protected]
    Decrypting info from the file system:  [email protected]
    

    두 경우의 최종 결과가 어떻게 유사한지 확인하십시오. 문자열을 작성하고 요청했을 때 동일한 문자열을 반환했습니다. 그러나 두 번째 경우에는 데이터를 저장하는 동안 암호화하고 읽는 동안 암호를 해독했습니다. 가장 중요한 부분은 이 모든 것이 사용자로부터 추상화된다는 것입니다.

    있습니다 - 데코레이터 패턴 🎉

    이제 데코레이터 패턴을 잘 이해했으므로 이것이 왜 좋은지 논의해 보겠습니다.
  • 처음부터 새 저장소를 만들 필요가 없었는지 확인하십시오. 이렇게 하면 많은 시간이 절약되고 스토리지 시스템의 API도 변경되지 않았습니다. 따라서 불행한 사용자는 없습니다.
  • 또한 EncryptedStorageSystemStorageSystem 인터페이스를 구현하고 임의의 StorageSystem를 둘러싸고 있음을 주목하십시오. 뿐만 아니라 GenericStorageSystem . 이것은 여러 재귀 래퍼를 만들 수 있기 때문에 매우 강력합니다. 이제 암호화한 후 데이터를 압축할 수도 있습니다. 💪🏽😁

  • Note: The Decorator pattern is different from the Adapter pattern because the adapter pattern converts one struct into another. Hence, there is a change in API. The decorator pattern, on the other hand, simply wraps around the existing struct without changing the API.



    이 튜토리얼의 모든 코드는 이것this github repo에서 찾을 수 있습니다.

    건배 ☕️

    좋은 웹페이지 즐겨찾기