2009-06-15 5 views
31

Was ist eine Proxy-Klasse in C++? Warum es erstellt wird und wo es nützlich ist?Was ist Proxy-Klasse in C++

+1

Proxy (unter vielen anderen Bedeutungen) ist ein ** Designmuster ** - siehe [Wikipedia ] (http://en.wikipedia.org/wiki/Proxy_pattern) für ausgezeichnete Abdeckung (nicht intensiv natürlich C++). –

+0

völlig zustimmen, gibt es ausgezeichnete Antworten hier auf diese Frage – vsoftco

Antwort

58

Ein Proxy ist eine Klasse, die eine geänderte Schnittstelle zu einer anderen Klasse bereitstellt. Hier ist ein Beispiel - nehmen wir an ein Array-Klasse haben, dass wir nur die binären Ziffern in der Lage sein wollen, enthalten 1 oder 0 Hier ist ein erster Versuch:

struct array1 { 
    int mArray[10]; 
    int & operator[](int i) { 
     /// what to put here 
    } 
}; ` 

Wir wollen Operator [] beschweren, wenn wir sagen, etwas wie a [1] = 42, aber das ist nicht möglich, weil der Operator nur den Index von in das Array sieht, nicht den Wert, der gespeichert wird.

Wir können diese über einen Proxy lösen:

#include <iostream> 
using namespace std; 

struct aproxy { 
    aproxy(int& r) : mPtr(&r) {} 
    void operator = (int n) { 
     if (n > 1) { 
      throw "not binary digit"; 
     } 
     *mPtr = n; 
    } 
    int * mPtr; 
}; 

struct array { 
    int mArray[10]; 
    aproxy operator[](int i) { 
     return aproxy(mArray[i]); 
    } 
}; 

int main() { 
    try { 
     array a; 
     a[0] = 1; // ok 
     a[0] = 42; // throws exception 
    } 
    catch (const char * e) { 
     cout << e << endl; 
    } 
} 

Die Proxy-Klasse jetzt tut unsere Prüfung eine Binärziffer und wir machen den Betreiber array [] eine Instanz des Proxy zurück, die auf dem begrenzten Zugang hat Array-Interna.

+1

Ich würde machen 'aproxy :: void operator = (int n)' zurück 'n' als ein 'int', da es Verkettung wie 'a [0 ermöglicht ] = a [1] = 0'. Andernfalls kopierst du eine 'aproxy', die von' a [1] = 0' zurückgegeben wird, in 'a [0]' und es funktioniert wie erwartet. Abgesehen davon, große und präzise Antwort! – vsoftco

2

A Proxy-Klasse können Sie verstecken die privaten Daten einer Klasse von Clients der Klasse.

Wenn Sie Clients Ihrer Klasse eine Proxyklasse zur Verfügung stellen, die nur die öffentliche Schnittstelle zu Ihrer Klasse kennt, können die Clients die Services Ihrer Klasse verwenden, ohne dass der Client auf die Implementierungsdetails Ihrer Klasse zugreifen muss.

8

Eine Proxy-Klasse in C++ wird verwendet, um die Proxy Pattern zu implementieren, in der ein Objekt eine Schnittstelle oder ein Vermittler für ein anderes Objekt ist.

Eine typische Verwendung einer Proxy-Klasse in C++ ist die Implementierung des [] -Operators, da der Operator [] zum Abrufen von Daten oder zum Festlegen von Daten innerhalb eines Objekts verwendet werden kann. Die Idee besteht darin, eine Proxy-Klasse bereitzustellen, die es ermöglicht, eine get-Datenverwendung des [] -Operators im Vergleich zu der eingestellten Datenverwendung des [] -Operators zu erkennen. Der [] -Operator einer Klasse verwendet das Proxy-Objekt, um das Richtige zu tun, indem erkannt wird, ob der Operator [] zum Abrufen oder Festlegen von Daten im Objekt verwendet wird.

Der C++ - Compiler wählt die entsprechenden Operatoren und Konvertierungsoperatoren aus der angegebenen Zielklasse und den Proxy-Klassendefinitionen aus, um den Operator [] besonders zu nutzen.

Es gibt jedoch andere Verwendungen für eine Proxy-Klasse in C++. Siehe zum Beispiel diesen Artikel auf Self-Registering Objects in C++ von Dr. Dobbs, der die Verwendung einer Proxy-Klasse als Teil einer Objektfabrik beschreibt. Die Objektfactory stellt einen bestimmten Objekttyp abhängig von einigen Kriterien bereit, in diesem Beispiel ein Grafikbildformat. Jeder der verschiedenen Grafikkonverter wird durch ein Proxy-Objekt repräsentiert.

Alle diese Anforderungen können durch die Verwendung eines „Fachgeschäft“ in , die es keinen einzigen Platz bei der Kompilierung in dem Code erfüllt werden, die über alle unterstützten Formate kennt. Die Liste der unterstützten Objekte wird unter Laufzeit erstellt, wenn jedes Objekt im Dateiformat seine Existenz mit einem Fachgeschäft Objekt registriert.

Es gibt vier Teile zum Aufbau einer Fachgeschäft:

  • Jede Klasse, die in den Laden geht, wird durch einen Proxy-Klasse dargestellt werden.Der Proxy weiß, wie Objekte für den Speicher erstellt werden, und bietet eine Standardschnittstelle für Informationen über die Klasse.
  • Sie müssen entscheiden, welche Kriterien das Fachgeschäft für Anrufer bereitstellen soll, und dann Schnittstellen für diese Kriterien im Geschäft implementieren, in der Proxy-Klasse und in der ursprünglichen Klasse.
  • Alle Proxy-Klassen werden von einer gemeinsamen Basisklasse abgeleitet, so dass das Fachgeschäft sie austauschbar verwenden kann. Jede Proxyklasse wird als Vorlage implementiert, die statische Funktionen in der ursprünglichen Klasse aufruft.
  • Proxy-Klassen werden beim Programmstart automatisch registriert, indem für jede Proxy-Klasse eine globale Variable definiert wird, deren Konstruktor die Proxy-Klasse beim Fachgeschäft registriert.

Ein anderes Beispiel wäre, wie Microsoft DCOM (Distributed COM) Objekte über einen Proxy auf dem Host-Rechner eines Benutzers des Objekts DCOM verwenden das eigentliche Objekt darzustellen, die auf einer anderen Host-Maschine befindet. Der Proxy stellt eine Schnittstelle für das tatsächliche Objekt auf einer anderen Maschine bereit und übernimmt die Kommunikation zwischen dem Benutzer des Objekts und dem tatsächlichen Objekt.

Zusammenfassend wird ein Proxy-Objekt als Vermittler zum eigentlichen Objekt verwendet. Ein Proxy-Objekt wird verwendet, wenn immer eine Art von Umwandlung oder Transformation zwischen dem Benutzer eines Objekts und dem tatsächlichen Objekt mit irgendeiner Art von Indirektion erforderlich ist, die einen Dienst bereitstellt, der die Verwendung des tatsächlichen Objekts ermöglicht, wenn ein Hindernis bei der Verwendung besteht das eigentliche Objekt direkt.

EDIT - Ein einfaches Beispiel einen Proxy mit Operator [] für einen einfachen Datenspeicher-Array

unter Verwendung der Quelle verwendet ein Proxy-Objekt für den Operator [] eine Klasse. Die Ausgabe der Test-Harness ist unten angegeben, um die Erzeugung und Zerstörung der verschiedenen Proxy-Objekte zu zeigen, da die Proxy-Klasse verwendet wird, um auf die tatsächliche Klasse zuzugreifen und sie zu manipulieren. Es ist lehrreich, dies in einem Debugger auszuführen, um die Ausführung zu beobachten.

// proxy.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include <string.h> 

#include <iostream> 

class TArrayProxy; 

// The actual class which we will access using a proxy. 
class TArray 
{ 
public: 
    TArray(); 
    ~TArray(); 

    TArrayProxy operator [] (int iIndex); 
    int operator = (TArrayProxy &j); 
    void Dump (void); 

    char m_TarrayName[4];  // this is the unique name of a particular object. 

    static char TarrayName[4]; // This is the global used to create unique object names 

private: 
    friend class TArrayProxy; // allow the proxy class access to our data. 
    int iArray[10];    // a simple integer array for our data store 
}; 

// The proxy class which is used to access the actual class. 
class TArrayProxy 
{ 
public: 
    TArrayProxy(TArray *p = 0, int i=0); 
    ~TArrayProxy(); 

    TArrayProxy & operator = (int i); 
    TArrayProxy & operator += (int i); 
    TArrayProxy & operator = (TArrayProxy &src); 
    operator int(); 

    int  iIndex; 
    char m_TarrayproxyName[4];  // this is the unique name of a particular object. 

    static char TarrayproxyName[4];  // This is the global used to create unique object names 

private: 
    TArray *pArray;      // pointer to the actual object for which we are a proxy. 
}; 

// initialize the object names so as to generate unique object names. 
char TArray::TarrayName[4] = {" AA"}; 
char TArrayProxy::TarrayproxyName[4] = {" PA"}; 

// Construct a proxy object for the actual object along with which particular 
// element of the actual object data store that this proxy will represent. 
TArrayProxy::TArrayProxy(TArray *p /* = 0 */, int i /* = 0 */) 
{ 
    if (p && i > 0) { 
     pArray = p; 
     iIndex = i; 
     strcpy (m_TarrayproxyName, TarrayproxyName); 
     TarrayproxyName[2]++; 
     std::cout << " Create TArrayProxy " << m_TarrayproxyName << " iIndex = " << iIndex << std::endl; 
    } else { 
     throw "TArrayProxy bad p"; 
    } 
} 

// The destructor is here just so that we can log when it is hit. 
TArrayProxy::~TArrayProxy() 
{ 
    std::cout << "  Destroy TArrayProxy " << m_TarrayproxyName << std::endl; 
} 

// assign an integer value to a data store element by using the proxy object 
// for the particular element of the data store. 
TArrayProxy & TArrayProxy::operator = (int i) 
{ 
    pArray->iArray[iIndex] = i; 
    std::cout << "  TArrayProxy assign = i " << i << " to " << pArray->m_TarrayName << " using proxy " << m_TarrayproxyName << " iIndex " << iIndex << std::endl; 
    return *this; 
} 

TArrayProxy & TArrayProxy::operator += (int i) 
{ 
    pArray->iArray[iIndex] += i; 
    std::cout << "  TArrayProxy add assign += i " << i << " to " << pArray->m_TarrayName << " using proxy " << m_TarrayproxyName << " iIndex " << iIndex << std::endl; 
    return *this; 
} 

// assign an integer value that is specified by a proxy object to a proxy object for a different element. 
TArrayProxy & TArrayProxy::operator = (TArrayProxy &src) 
{ 
    pArray->iArray[iIndex] = src.pArray->iArray[src.iIndex]; 
    std::cout << "  TArrayProxy assign = src " << src.m_TarrayproxyName << " iIndex " << src.iIndex << " to " << m_TarrayproxyName << " iIndex "<< iIndex << " from" << std::endl; 
    return *this; 
} 

TArrayProxy::operator int() 
{ 
    std::cout << "  TArrayProxy operator int " << m_TarrayproxyName << " iIndex " << iIndex << " value of " << pArray->iArray[iIndex] << std::endl; 
    return pArray->iArray[iIndex]; 
} 



TArray::TArray() 
{ 
    strcpy (m_TarrayName, TarrayName); 
    TarrayName[2]++; 
    std::cout << " Create TArray = " << m_TarrayName << std::endl; 
    for (int i = 0; i < sizeof(iArray)/sizeof(iArray[0]); i++) { iArray[i] = i; } 
} 

// The destructor is here just so that we can log when it is hit. 
TArray::~TArray() 
{ 
    std::cout << " Destroy TArray " << m_TarrayName << std::endl; 
} 

TArrayProxy TArray::operator [] (int iIndex) 
{ 
    std::cout << " TArray operator [" << iIndex << "] " << m_TarrayName << std::endl; 
    if (iIndex > 0 && iIndex <= sizeof(iArray)/sizeof(iArray[0])) { 
     // create a proxy object for this particular data store element 
     return TArrayProxy(this, iIndex); 
    } 
    else 
     throw "Out of range"; 
} 

int TArray::operator = (TArrayProxy &j) 
{ 
    std::cout << " TArray operator = " << m_TarrayName << " from" << j.m_TarrayproxyName << " index " << j.iIndex << std::endl; 
    return j.iIndex; 
} 

void TArray::Dump (void) 
{ 
    std::cout << std::endl << "Dump of " << m_TarrayName << std::endl; 
    for (int i = 0; i < sizeof(iArray)/sizeof(iArray[0]); i++) { 
     std::cout << " i = " << i << " value = " << iArray [i] << std::endl; 
    } 
} 

// ----------------- Main test harness follows ---------------- 
// we will output the line of code being hit followed by the log of object actions. 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    TArray myObj; 

    std::cout << std::endl << "int ik = myObj[3];" << std::endl; 
    int ik = myObj[3]; 
    std::cout << std::endl << "myObj[6] = myObj[4] = 40;" << std::endl; 
    myObj[6] = myObj[4] = 40; 
    std::cout << std::endl << "myObj[5] = myObj[5];" << std::endl; 
    myObj[5] = myObj[5]; 
    std::cout << std::endl << "myObj[2] = 32;" << std::endl; 
    myObj[2] = 32; 
    std::cout << std::endl << "myObj[8] += 20;" << std::endl; 
    myObj[8] += 20; 
    myObj.Dump(); 
    return 0; 
} 

Und hier ist der Ausgang dieses Beispiels von einer Konsolenanwendung mit Visual Studio 2005.

Create TArray = AA 

int ik = myObj[3]; 
    TArray operator [3] AA 
    Create TArrayProxy PA iIndex = 3 
     TArrayProxy operator int PA iIndex 3 value of 3 
     Destroy TArrayProxy PA 

myObj[6] = myObj[4] = 40; 
    TArray operator [4] AA 
    Create TArrayProxy PB iIndex = 4 
     TArrayProxy assign = i 40 to AA using proxy PB iIndex 4 
    TArray operator [6] AA 
    Create TArrayProxy PC iIndex = 6 
     TArrayProxy assign = src PB iIndex 4 to PC iIndex 6 from 
     Destroy TArrayProxy PC 
     Destroy TArrayProxy PB 

myObj[5] = myObj[5]; 
    TArray operator [5] AA 
    Create TArrayProxy PD iIndex = 5 
     TArrayProxy operator int PD iIndex 5 value of 5 
    TArray operator [5] AA 
    Create TArrayProxy PE iIndex = 5 
     TArrayProxy assign = i 5 to AA using proxy PE iIndex 5 
     Destroy TArrayProxy PE 
     Destroy TArrayProxy PD 

myObj[2] = 32; 
    TArray operator [2] AA 
    Create TArrayProxy PF iIndex = 2 
     TArrayProxy assign = i 32 to AA using proxy PF iIndex 2 
     Destroy TArrayProxy PF 

myObj[8] += 20; 
    TArray operator [8] AA 
    Create TArrayProxy PG iIndex = 8 
     TArrayProxy add assign += i 20 to AA using proxy PG iIndex 8 
     Destroy TArrayProxy PG 

Dump of AA 
    i = 0 value = 0 
    i = 1 value = 1 
    i = 2 value = 32 
    i = 3 value = 3 
    i = 4 value = 40 
    i = 5 value = 5 
    i = 6 value = 40 
    i = 7 value = 7 
    i = 8 value = 28 
    i = 9 value = 9