현대 C 언어의 프록시 디자인 모드++

소프트웨어 공학에서 구조 설계 모델 처리 대상 간의 관계, 즉 대상/류가 어떻게 상호작용을 하거나 상황에 적합한 방식으로 관계를 맺는지.구조 설계 모델은 식별 관계를 통해 구조를 간소화한다.이 구조화된 디자인 모델의 글에서 우리는 C++의 프록시 디자인 모델을 볼 것이다. 이것은 방문 대상의 방식을 규정하고 있다.

/!\: This article has been originally published on my blog. If you are interested in receiving my latest articles, please sign up to my newsletter.


다른 구조 설계 모드를 아직 보지 않은 경우 목록은 다음과 같습니다.
  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy
  • 이 시리즈에서 본 코드 세션은 복잡하지 않고 간략합니다.그래서 나는 override, final, public, (while inheritation) 같은 키워드를 사용하지 않는 것을 자주 본다. 단지 하나의 표준 화면 크기에서 코드를 촘촘하고 사용하기 쉽기 위해서이다(대다수 경우).나도 struct를 더 좋아한다. class는 때때로 "public:"를 쓰지 않고 줄을 저장하고 일부러 놓친다virtual destructor, 구조 함수copy constructor, 접두사std::, 동적 메모리를 삭제한다.나는 또한 내가 실용적인 사람이라고 생각하고 가능한 한 간단한 방식으로 생각을 표현하고 표준적인 방식이나 행화가 아니라 희망한다.
    참고:
  • 만약 네가 여기서 직접 걸려 넘어진다면, 나는 네가 먼저 통과할 것을 건의한다What is design pattern?. 설령 그것이 보잘것없다 하더라도.나는 이것이 네가 이 화제에서 더 많은 탐색을 하도록 격려할 것이라고 믿는다.
  • 이 시리즈에서 만났던 모든 코드는 C++20으로 컴파일되었습니다. (대부분의 경우 Modern C++ C++17 이전의 기능을 사용했지만.)따라서 최신 컴파일러에 접근할 수 없으면 https://wandbox.org/ 을 사용할 수 있으며, 보스 라이브러리도 미리 설치되어 있습니다.

  • 의 의도

    An interface for accessing a particular resource.

  • 에이전트는 특정 자원의 인터페이스를 충당한다. 이 자원은 원격, 구축 비용이 높거나 로그 기록이나 다른 기능과 같은 추가 기능이 필요할 수 있다.
  • 그러나 에이전트의 관건은 인터페이스가 실제 방문하려는 object 인터페이스처럼 보인다는 것입니다.이 인터페이스는 방법, 재부팅 연산자, 또는 다른 다른 다른/로컬 클래스 object 일 수 있습니다.

  • C 언어의 프록시 디자인 모드 예시++
  • C++에서 매우 복잡한 프록시 디자인 모델의 예로 매일 사용할 수 있습니다. 이것은 표준 라이브러리의 하나smart pointer(예를 들어 std::unique_ptr,std::shared_ptr 등)
  • // Ways to access object through pointer
    ptr->print();
    *ptr = 5;
    
  • 왜 스마트 포인터가 에이전트가 되는지 설명해 드릴게요.위의 코드 세션만 보면 ptr가 원시 바늘인지 스마트 바늘인지 확인할 수 없습니다.
  • 따라서 스마트 포인터는 에이전트이다. 왜냐하면 그들은 에이전트 조건, 즉
  • 자원에 접근하는 인터페이스를 제공합니다.
  • 인터페이스가 대상의 인터페이스처럼 보인다.
  • 원격 에이전트, 가상 에이전트, 보호 에이전트, 통신 에이전트 등 다양한 유형의 에이전트를 사용할 수 있습니다.우리는 이곳에서 그중의 일부를 볼 것이다.

  • 재산 대리
  • 알 수 있는 다른 프로그래밍 언어와 같이 C# have this idea of properties.한 필드만 이 필드의 Getter와setter 방법을 추가할 수 있습니다.만약 우리가 C++에서 속성을 얻으려고 한다면, 우리는 Property 클래스를 다음과 같이 작성할 것이다.
  • template<typename T>
    struct Property {
        T   m_value;
    
        Property(const T initialValue) { * this = initialValue; }
        operator T() { return m_value; }
        T operator = (T newValue) { return m_value = newValue; }
    };
    
    struct Creature {
        Property<int32_t>   m_strength{10};
        Property<int32_t>   m_agility{5};
    };
    
    int main() {
        Creature creature;
        creature.m_agility = 20;
        cout << creature.m_agility << endl;
        return EXIT_SUCCESS;
    }
    
  • 그런데 위의 코드를 보면 우리가 왜 strengthagilityint32_t로 성명하지 않았는지 생각할 수 있습니다.어떤 이유로 이 필드에 대한 접근을 차단하거나 기록해야 한다고 가정해 봅시다.따라서 모든 속성을 위한 Getter &setter 방법이 아니라 Property로 효과적인 방법이 필요합니다.

  • 가상 에이전트
  • 그래서 어느 순간에 당신이 만나게 될 또 다른 유형의 에이전트는 이른바 가상 에이전트입니다.현재 가상 에이전트는 당신이 사용했던 같은 대상을 사용하고 있는 것처럼 보입니다. 설령 이 대상이 아직 만들어지지 않았을지라도.
  • struct Image {
        virtual void draw() = 0;
    };
    
    struct Bitmap : Image {
        Bitmap(const string &filename) : m_filename(filename) {
            cout << "Loading image from " << m_filename << endl;
            // Steps to load the image
        }
        void draw() { cout << "Drawing image " << m_filename << endl; }
    
        string      m_filename;
    };
    
    int main() {
        Bitmap img_1{"image_1.png"};
        Bitmap img_2{"image_2.png"};
    
        (rand() % 2) ? img_1.draw() : img_2.draw();
    
        return EXIT_SUCCESS;
    }
    
  • 위에서 보듯이 Bitmap 이미지는 Image 인터페이스에서 파생된 것으로 이 인터페이스는 다태적 행위를 가진다draw().Bitmap 그림을 구조 함수에 급히 불러옵니다.
  • 언뜻 보기에는 괜찮은 것 같지만 Bitmap의 문제는 그림 코드가 시작되기 전에 그림을 불러올 필요가 없다는 것이다.따라서 구축할 때 두 개의 이미지를 메모리에 불러오는 것은 무의미하다.
  • 현재 변경 없이 상술한 코드를 개선하는 방법을 보여 드리겠습니다.제3자 라이브러리를 사용할 때 이런 기술은 매우 유용하기 때문에 이를 둘러싸고 포장기를 작성하여 성능을 향상시키기를 원합니다.
  • struct LazyBitmap : Image {
        LazyBitmap(const string &filename) : m_filename(filename) {}
        void draw() {
            if (!m_bmp) m_bmp = make_unique<Bitmap>(m_filename);
            m_bmp->draw();
        }
    
        unique_ptr<Bitmap>      m_bmp{nullptr};
        string                  m_filename;
    };
    
    LazyBitmap img_1{"image_1.png"};
    LazyBitmap img_2{"image_2.png"};
    
  • 보시다시피 우리는 Bitmap가 필요하기 전에 그것을 사용하지 않습니다.반대로 그림을 그리려는 사람이 만들 수 있도록 파일 이름만 캐시합니다. Bitmap따라서 그림을 그리려는 사람이 없다면 파일에서 그림을 불러오는 것은 무의미하다.

  • 통신 에이전트 (C++의 직관 에이전트 디자인 모드)
  • 통신 에이전트는 C++에서 가장 흔하고 직관적인 에이전트 디자인 모델이다.통신 에이전트의 직접적인 예는 하위 연산자 재부팅이다.다음 사용자정의 유형의 예제인 Bitmap를 고려하면 기본 유형의 2D 배열과 동일한 방식으로 작동합니다.
  • template <typename T>
    struct arr2D {
        struct proxy {
            proxy(T *arr) : m_arr_1D(arr) {}
            T &operator[](int32_t idx) {
                return m_arr_1D[idx];
            }
    
            T   *m_arr_1D;
        };
    
        arr2D::proxy operator[](int32_t idx) {
            return arr2D::proxy(m_arr_2D[idx]);
        }
    
        T   m_arr_2D[10][10];
    };
    
    int main() {
        arr2D<int32_t> arr;
        arr[0][0] = 1;  // Uses the proxy object
        return EXIT_SUCCESS;
    }
    

    대리 디자인 모델의 장점
  • 이 에이전트는 복잡한 데이터 배정에도 우호적이고 간단한 인터페이스를 제공한다.
  • 프록시 디자인 모델(특히 가상 프록시)도 성능 개선을 제공했다. 위의 지연 이미지 마운트 사례에서 보듯이.
  • Property proxy는 클라이언트가 모르는 상황에서 대상 속성에 대한 접근을 기록하는 유연성을 제공합니다.

  • FAQ 요약
    Decorator와 Proxy 디자인 모델이 같습니까?
    그것들은 약간 비슷하지만 용도가 다르다.예를 들어 위의 예를 고려하면 에이전트는 보통 생명주기 & 대상에 대한 접근을 관리하고 장식기는 원시 대상의 포장으로 더 많은 기능을 가진다.
    어댑터, 장식기와 프록시 디자인 모델 사이의 차이는?
    - 어댑터는 포장된 객체에 대해 서로 다른/호환 가능한 인터페이스를 제공합니다.
    -- Proxy는 대개 동일하거나 간단한 인터페이스를 제공합니다.
    -- Decorator는 향상된 인터페이스를 제공합니다.
    대리 디자인 모델의 용례는 무엇입니까?
    - 객체가 자원을 소비하고 대부분의 시간을 디스크에 저장하는 경우 위의 불활성 이미지 로드에서 수행한 것처럼 프록시를 자리 표시자로 사용할 수 있습니다.
    - 객체에 대한 읽기 전용 액세스나 사용자 기반 액세스 제어 등의 액세스 제한을 실제 작업을 수행하기 전에 추가하려는 경우(예: 사용자가 승인을 받은 경우 해당 작업을 수행하고 승인이 없는 경우 액세스 제어 예외가 발생)

    좋은 웹페이지 즐겨찾기