2009-06-15 44 views
31

¿Qué es una clase Proxy en C++? ¿Por qué se crea y dónde es útil?¿Qué es Proxy Class en C++

+1

Proxy (entre muchos otros significados) es un patrón de diseño ** ** - véase [Wikipedia ] (http://en.wikipedia.org/wiki/Proxy_pattern) para una excelente cobertura (no intensamente específica de C++, por supuesto). –

+0

completamente de acuerdo, hay respuestas excelentes proporcionadas aquí a esta pregunta – vsoftco

Respuesta

58

Un proxy es una clase que proporciona una interfaz modificada a otra clase. Aquí está un ejemplo - supongamos que tenemos una clase de matriz que sólo queremos ser capaz de contener los dígitos binarios 1 ó 0. Aquí es un primer intento:

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

Queremos operador [] para quejarse si decimos algo así como a [1] = 42, pero eso no es posible porque el operador solo ve el índice de la matriz, no el valor que se almacena.

Podemos resolver esto utilizando un proxy:

#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; 
    } 
} 

La clase proxy hace ahora nuestra comprobación de un dígito binario y hacemos operador de la matriz [] devolver una instancia de la representación que tiene un acceso limitado a la los internos de la matriz.

+1

Haría que 'aproxy :: void operator = (int n)' devuelva 'n' como' int', ya que permitirá el encadenamiento como 'a [0 ] = a [1] = 0'. De lo contrario, está copiando un 'aproxy' que' a [1] = 0' devuelve en 'a [0]', y está funcionando como se esperaba. ¡Aparte de eso, respuesta grandiosa y concisa! – vsoftco

2

Una clase de proxy le permite ocultar los datos privados de una clase de clientes de la clase.

Proporcionar a los clientes de su clase una clase proxy que solo conoce la interfaz pública de su clase permite a los clientes utilizar los servicios de su clase sin dar acceso al cliente a los detalles de implementación de su clase.

8

Una clase proxy en C++ se utiliza para implementar el Proxy Pattern en el que un objeto es una interfaz o un mediador para algún otro objeto.

Un uso típico de una clase proxy en C++ está implementando el operador [] ya que el operador [] se puede usar para obtener datos o establecer datos dentro de un objeto. La idea es proporcionar una clase proxy que permita la detección de un uso de obtención de datos del operador [] frente al uso de datos establecidos del operador []. El operador [] de una clase usa el objeto proxy para ayudar a hacer lo correcto al detectar si el operador [] se está utilizando para obtener o establecer datos en el objeto.

El compilador C++ selecciona los operadores apropiados y los operadores de conversión de la clase objetivo proporcionada y las definiciones de la clase proxy para hacer un uso particular del trabajo del operador [].

Sin embargo, hay otros usos para una clase proxy en C++. Por ejemplo, consulte este artículo en Self-Registering Objects in C++ del Dr. Dobbs que describe el uso de una clase proxy como parte de una fábrica de objetos. La fábrica de objetos proporciona un tipo particular de objeto dependiendo de algunos criterios, en este ejemplo, un formato de imagen gráfica. Cada uno de los diferentes convertidores de imágenes gráficas está representado por un objeto proxy.

Todos estos requisitos se pueden satisfacer mediante el uso de una "tienda especializada" en la que no hay un único lugar del código en tiempo de compilación que se sabe acerca todos los formatos soportados. La lista de objetos admitidos se compila en tiempo de ejecución cuando cada objeto de formato de archivo registra su existencia con un objeto de tienda especializada .

Hay cuatro partes a la construcción de una tienda de especialidad:

  • Cada clase que va en la tienda estará representada por una clase de proxy.El proxy sabe cómo crear objetos para la tienda y proporciona una interfaz estándar para obtener información sobre la clase.
  • Debe decidir qué criterios expondrá la tienda especializada a las personas que llaman, luego implementar interfaces para esos criterios en la tienda, en la clase proxy, y en la clase original.
  • Todas las clases de proxy se derivarán de una clase base común para que la tienda especializada pueda usarlas indistintamente. Cada clase de proxy será implementada como una plantilla que llama a funciones estáticas en la clase original .
  • Las clases proxy se registrarán automáticamente al inicio del programa definiendo una variable global para cada clase proxy cuyo constructor registrará la clase proxy con el almacén especializado.

Otro ejemplo sería cómo Microsoft DCOM (Distributed COM) objetos usan un proxy en la máquina anfitrión de un usuario del objeto DCOM para representar el objeto real que reside en otra máquina host. El proxy proporciona una interfaz para el objeto real en una máquina diferente y maneja la comunicación entre el usuario del objeto y el objeto real.

En resumen, un objeto proxy se utiliza para actuar como intermediario para el objeto real. Un objeto proxy se utiliza cuando debe haber algún tipo de conversión o transformación entre el usuario de un objeto y el objeto real con algún tipo de indirección que proporciona un servicio que permite el uso del objeto real cuando hay algún obstáculo en el uso el objeto real directamente.

EDITAR - Un simple ejemplo usando un proxy con operador [] para un simple almacén de datos array

la siguiente fuente utiliza un objeto proxy para el operador [] de una clase. La salida del arnés de prueba se proporciona a continuación para mostrar la creación y destrucción de los diversos objetos proxy, ya que la clase proxy se usa para acceder y manipular la clase real. Es instructivo ejecutar esto en un depurador para verlo ejecutar.

// 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; 
} 

Y aquí es la salida de este ejemplo de una aplicación de consola con 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