Proxy Model


Note: In the context of Qt MVC, a Proxy Model is a Model Pipe design.
Django also defines a Proxy Model concept, but it is unrelated to the one
expressed here: the application of the Proxy design pattern to a Model object.


Motivation

We want to access an external resource, such as one provided by an HTTP
server or a database. Proxy Model encapsulate the logic needed to access
the remote service, specifically:

  • Issue the request to the remote service
  • Handle error conditions
  • Convert received data into a representation useful for the client code.

Additionally, the Proxy Model can:

  • Throttle an excessive number of requests in a short amount of time
  • Cache obtained results and manage the cache expiration
  • Observe the remote service for changes, for example through
    polling on a secondary thread.

Design

The design of a Proxy Model is generally dependent on the service it
represents. Interfaces are designed to comply with the abstraction of the
remote service. When the client code asks for data, the Model issues the
appropriate request to the service provider. Client code is generally
unaware of the exact nature of the backend exposed by the Proxy Model.


Proxy Model - 图1

When the Model implements SQL access to a specific database table, the resulting
Proxy Model is normally called Table Data Gateway. An instance of this Model
represents the backend database Table as a whole, not a specific row, and its
methods provide access to CRUD operations.

Practical example: Django Models

A simple Django Model provides an example of a Proxy Model.

  1. from django.db import models
  2. class Person(models.Model):
  3. first_name = models.CharField(max_length=30)
  4. last_name = models.CharField(max_length=30)

For the class definition given above, Django’s internals create a SQL table
whose columns are defined by the class properties (first_name and last_name).
Instances of the Person class are represented as table rows.

The Person class can be instantiated, stored in the database, modified, or
used to retrieve an already present instance.

  1. person = Person(first_name="A.", last_name="Einstein")
  2. person.save()
  3. person.first_name = "Albert"
  4. person.save()
  5. another_person = Person.objects.get(last_name="Galilei")

Under the hood, the Django Model implementation converts the operations into SQL statements.

Practical example: Thrift services

Another example of Proxy Model is provided by Thrift, a cross-language Remote Procedure Call
framework. An Interface Definition Language specifies the interface of the remote service

  1. service Calculator {
  2. i32 add(1:i32 num1, 2:i32 num2),
  3. }

which is compiled into python to generate the following code

  1. class Client(Iface):
  2. def __init__(self, iprot, oprot=None):
  3. self._iprot = self._oprot = iprot
  4. if oprot is not None:
  5. self._oprot = oprot
  6. self._seqid = 0
  7. def add(self, num1, num2):
  8. """
  9. Parameters:
  10. - num1
  11. - num2
  12. """
  13. self.send_add(num1, num2)
  14. return self.recv_add()
  15. def send_add(self, num1, num2):
  16. self._oprot.writeMessageBegin('add', TMessageType.CALL, self._seqid)
  17. args = add_args()
  18. args.num1 = num1
  19. args.num2 = num2
  20. args.write(self._oprot)
  21. self._oprot.writeMessageEnd()
  22. self._oprot.trans.flush()
  23. def recv_add(self):
  24. iprot = self._iprot
  25. (fname, mtype, rseqid) = iprot.readMessageBegin()
  26. if mtype == TMessageType.EXCEPTION:
  27. x = TApplicationException()
  28. x.read(iprot)
  29. iprot.readMessageEnd()
  30. raise x
  31. result = add_result()
  32. result.read(iprot)
  33. iprot.readMessageEnd()
  34. if result.success is not None:
  35. return result.success
  36. raise TApplicationException(TApplicationException.MISSING_RESULT,
  37. "add failed: unknown result")

The above Proxy handles the complexity of the network exchange, providing a simple interface to
client code

  1. result = client.add(3, 4)

References