© Dmitri Nesteruk 2020
D. NesterukDesign Patterns in .NET Core 3https://doi.org/10.1007/978-1-4842-6180-4_13

13. Proxy

Dmitri Nesteruk1  
(1)
St. Petersburg, c.St-Petersburg, Russia
 

When we looked at the Decorator design pattern, we saw the different ways of enhancing the functionality of an object. The Proxy design pattern is similar, but its goal is generally to preserve exactly (or as closely as possible) the API that is being used while offering certain internal enhancements.

Proxy is an unusual design pattern in that it isn’t really homogeneous. The many different kinds of proxies people build are quite numerous and serve entirely different purposes. In this chapter we’ll take a look at a selection of different proxy objects, and you can find more online.

Protection Proxy

The idea of a protection proxy , as the name suggests, is to provide access control to an existing object. For example, you might be starting out with an object called Car that has a single Drive() method that lets you drive the car (here we go, another synthetic example).
public class Car // : ICar
{
  public void Drive()
  {
    WriteLine("Car being driven");
  }
}
But, later on, you decide that you want to only let people drive the car if they are old enough. What if you don’t want to change Car itself and you want the extra checks to be done somewhere else (SRP)? Let’s see… first, you extract the ICar interface (note this operation doesn’t affect Car in any significant way):
public interface ICar
{
  void Drive();
}
The protection proxy we’re going to build is going to depend on a Driver that’s defined like this :
public class Driver
{
  public int Age { get; set; }
  public Driver(int age)
  {
    Age = age;
  }
}
The proxy itself is going to take a Driver in the constructor and it’s going to expose the same ICar interface as the original car, the only difference being that some internal checks occur making sure the driver is old enough:
public class CarProxy : ICar
{
  private Car car = new Car();
  private Driver driver;
  public CarProxy(Driver driver)
  {
    this.driver = driver;
  }
  public void Drive()
  {
    if (driver.Age >= 16)
      car.Drive();
    else
    {
      WriteLine("Driver too young");
    }
  }
}
Here is how one would use this proxy:
ICar car = new CarProxy(new Driver(12));
car.Drive(); // Driver too young
There’s one piece of the puzzle that we haven’t really addressed. Even though both Car and CarProxy implement ICar, their constructors are not identical! This means that, strictly speaking, the interfaces of the two objects are not strictly identical. Is this a problem? This depends
  • If your code was dependent on Car rather than ICar (violating DIP), then you would need to search and replace every use of this type in your code. Not impossible with tools like ReSharper/Rider, just really annoying.

  • If your code was dependent on ICar but you were explicitly invoking Car constructors, you would have to find all those constructor invocations and feed each of them a Driver.

  • If you were using dependency injection, you are good to go provided you register a Driver in the container.

So, among other things, the protection proxy we’ve built is an illustration of the benefits of using an IoC container with constructor injection support.

Property Proxy

C# makes the use of properties easy: you can use either “full” or automatic properties , and now there’s expression-based notation for getters and setters, so you can keep properties really concise. However, that’s not always what you want: sometimes, you want a getter or setter of each property in your code to do something in addition to just the default actions. For example, you might want setters that prevent self-assignment and also (for illustrative purposes) output some info about what value is being assigned and to what property.

So instead of using ordinary properties, you might want to introduce a property proxy – a class that, for all intents and purposes, behaves like a property but is actually a separate class with domain-specific behaviors (and associated performance costs). You would start building this class by wrapping a simple value and adding whatever extra information you want the property to have (e.g., the property name):
public class Property<T> where T : new()
{
  private T value;
  private readonly string name;
  public T Value
  {
    get => value;
    set
    {
       if (Equals(this.value, value)) return;
       Console.WriteLine($"Assigning {value} to {name}");
       this.value = value;
    }
  }
  public Property() : this(default(T)) {}
  public Property(T value, string name = "")
  {
    this.value = value;
    this.name = name;
  }
}
For now, all we have is a simple wrapper, but where’s the proxy part of it all? After all, we want a Property<int> to behave as close to an int as possible. To that end, we can define a couple of implicit conversion operators:
public static implicit operator T(Property<T> property)
{
  return property.Value; // int n = p_int;
}
public static implicit operator Property<T>(T value)
{
  return new Property<T>(value); // Property<int> p = 123;
}

The first operator lets us implicitly convert the property type to its underlying value; the second operator lets us initialize a property from a value (without a name, of course). Sadly, C# does not allow us to override the assignment = operator.

How would you use this property proxy? Well, there are two ways I can think of. One, and the most obvious , is to expose the property as a public field:
public class Creature
{
  public Property<int> Agility
    = new Property<int>(10, nameof(Agility))
}
Unfortunately, this approach is not a “proper” proxy because while it replicates the interface of an ordinary property, it doesn’t give us the behavior we want:
var c = new Creature();
c.Agility = 12; // <nothing happens!>

When you assign a value, as you would with an ordinary property, absolutely nothing happens. Why? Well, the reason is that we invoked the implicit conversion operator which, instead of changing an existing property, just gave us a new property instead! It’s definitely not what we wanted, and furthermore, we’ve lost the name value as it was never propagated by the operator.

So the solution here, if we really want the property to both look like a duck and quack like a duck, is to create a wrapper (delegating) property and keep the proxy as a private backing field:
public class Creature
{
  public readonly Property<int> agility
    = new Property<int>(10, nameof(agility));
  public int Agility
  {
    get => agility.Value;
    set => agility.Value = value;
  }
}
With this approach, we finally get the desired behavior:
var c = new Creature();
c.Agility = 12; // Assigning 12 to Agility

Purists might argue that this isn’t an ideal proxy (since we’ve had to generate both a new class as well as rewrite an existing property), but this is purely a limitation of the C# programming language.

Value Proxy

A value proxy is a proxy around a primitive value, such as an integer. Why would you want such a proxy? Well, it’s because certain primitive values can have special meanings.

Consider percentages. Multiplying by 50 is different from multiplying by 50% because the latter is really multiplication by 0.5. But you still want to refer to 50% as 50% in your code, right? Let’s see if we can build a Percentage type.

First of all, we need to agree on construction. Let’s assume that we do, in fact, store a decimal behind the scenes that is actually a multiplier. In that case, we can begin our Percentage class as follows:
[DebuggerDisplay("{value*100.0f}%")]
public struct Percentage
{
  private readonly decimal value;
  internal Percentage(decimal value)
  {
    this.value = value;
  }
  // more members here
}
We have different choices for how to actually construct percentage values. One approach would be to adopt extension methods :
public static class PercentageExtensions
{
  public static Percentage Percent(this int value)
  {
    return new Percentage(value/100.0m);
  }
  public static Percentage Percent(this decimal value)
  {
    return new Percentage(value/100.0m);
  }
}
We want this percentage to act the same as percentage values in, for example, Microsoft Excel. Multiplying by 50% should effectively multiply by 0.5; other operations should work in a similar fashion. Thus, we need to define many operators such as
public static decimal operator *(decimal f, Percentage p)
{
  return f * p.value;
}
Let’s not forget that percentage can also operate on other percentages: for example, you can add 5% and 10% together and, similarly, you can take 50% of 50% (getting 25%). So you need more operators such as
public static Percentage operator +(Percentage a, Percentage b)
{
  return new Percentage(a.value + b.value);
}
In addition, you need the usual trappings: Equals(), GetHashCode(), and a meaningful ToString() such as
public override string ToString()
{
  return $"{value*100}%";
}
And that’s your value proxy. Now, if you need to operate on percentages in your application and store them explicitly as percentages, you can do so .
Console.WriteLine(10m * 5.Percent());          // 0.50
Console.WriteLine(2.Percent() + 3m.Percent()); // 5.00%

Composite Proxy: SoA/AoS

Many applications, such as game engines, are very sensitive to data locality. For example, consider the following class:
class Creature
{
  public byte Age;
  public int X, Y;
}
If you had several creatures in your game, kept in an array, the memory layout of your data would appear as
Age X Y Age X Y Age X Y ... and so on

This means that if you wanted to update the X coordinate of all objects in an array, your iteration code would have to jump over the other fields to get each of the Xs.

Turns out that CPUs generally like data locality, that is, data being kept together. This is often called the AoS/SoA (Array of Structures/Structure of Arrays ) problem. For us, it would be much better if the memory layout was in SoA form, as follows:
Age Age Age ... X X X ... Y Y Y

How can we achieve this? Well, we can build a data structure that keeps exactly such a layout and then expose Creature objects as proxies.

Here’s what I mean. First of all, we create a Creatures collection (I use arrays as underlying data types) that enforces data locality for each of the “fields”:
class Creatures
{
  private readonly int size;
  private byte [] age;
  private int[] x, y;
  public Creatures(int size)
  {
    this.size = size;
    age = new byte[size];
    x = new int[size];
    y = new int[size];
  }
}
Now, a Creature type can be constructed as a hollow proxy (a stateless proxy/memento amalgamation) that points to an element within the Creatures container .
public struct Creature
{
  private readonly Creatures creatures;
  private readonly int index;
  public Creature(Creatures creatures, int index)
  {
    this.creatures = creatures;
    this.index = index;
  }
  public ref byte Age => ref creatures.age[index];
  public ref int X => ref creatures.x[index];
  public ref int Y => ref creatures.y[index];
}

Note that the preceding class is nested within Creatures. The reason for this is that its property getters need to access private members of Creatures, which would be impossible if the class was on the same scope as the container.

So now that we have this proxy, we can give the Creatures container additional features, such as an indexer or a GetEnumerator() implementation :
public class Creatures
{
  // members here
  public Creature this[int index]
    => new Creature(this, index);
  public IEnumerator<Creature> GetEnumerator()
  {
    for (int pos = 0; pos < size; ++pos)
      yield return new Creature(this, pos);
  }
}
And that’s it! We can now look at a side-by-side comparison of the AoS approach and the new SoA approach:
// AoS
var creatures = new Creature[100];
foreach (var c in creatures)
{
  c.X++; // not memory-efficient
}
// SoA
var creatures2 = new Creatures(100);
foreach (var c in creatures2)
{
  c.X++;
}

Naturally, what I’ve shown here is a simplistic model. It would be more useful with arrays replaced by more flexible data structures like List<T>, and a lot more features could be added in order to make Creatures even more user-friendly.

Composite Proxy with Array-Backed Properties

Suppose you’re working on an application that generates bricklaying designs. You need to decide what surfaces you want to cover with bricks, so you make a list of checkboxes as follows:
  • Pillars

  • Walls

  • Floors

  • All

Most of these are easy and can be bound one-to-one to boolean variables , but the last option, All, cannot. How would you implement it in code? Well, you could try something like the following:
public class MasonrySettings
{
  public bool Pillars, Walls, Floors;
  public bool All
  {
    get { return Pillars && Walls && Floors; }
    set {
      Pillars = value;
      Walls = value;
      Floors = value;
   }
  }
}
This implementation might work, but it’s not 100% correct. The last checkbox called All is actually not even boolean because it can be in three states:
  • Checked if all items are checked

  • Unchecked if all items are unchecked

  • Grayed if some items are checked and others are not

This makes it a bit of a challenge: how do we make a variable for the state of this element that can be reliably bound to UI?

First of all, those combinations using && are ugly. We already have a tool called Array-Backed Properties that can help us take care of that, transforming the class to
public class MasonrySettings
{
  private bool[] flags = new bool[3];
  public bool Pillars
  {
    get => flags[0];
    set => flags[0] = value;
  }
  // similar for Floors and Walls
}
Now, care to guess what type the All variable should have? Personally I’d go for a bool? (a.k.a. Nullable<bool>) where the null can indicate an indeterminate state. This means that we check the homogeneity of each element in the array and return its first element if it’s homogeneous (i.e., all elements are the same) and null otherwise:
public bool? All
{
  get
  {
    if (flags.Skip(1).All(f => f == flags[0]))
      return flags[0];
    return null;
  }
  set
  {
    if (!value.HasValue) return;
    for (int i = 0; i < flags.Length; ++i)
      flags[i] = value.Value;
  }
}

The getter earlier is fairly self-explanatory. When it comes to the setter, its value gets assigned to every element in the array. If the passed-in value is null, we don’t do anything. An alternative implementation could, for example, flip every Boolean member inside the array – your choice!

Virtual Proxy

There are situations where you only want the object constructed when it’s accessed, and you don’t want to allocate it prematurely. If this was your starting strategy, you would typically use a Lazy<T> or similar mechanism, feeding the initialization code into its constructor lambda. However, there are situations when you are adding lazy instantiation at a later point in time, and you cannot change the existing API.

In this situation, what you end up building is a virtual proxy: an object that has the same API as the original, giving the appearance of an instantiated object, but behind the scenes, the proxy only instantiates the object when it’s actually necessary.

Imagine a typical image interface:
interface IImage
{
  void Draw();
}
An eager (opposite of lazy) implementation of a Bitmap (nothing to do with System.Drawing.Bitmap!) would load the image from a file on construction, even if that image isn’t actually required for anything. And yes, the following code is an emulation:
class Bitmap : IImage
{
  private readonly string filename;
  public Bitmap(string filename)
  {
    this.filename = filename;
    WriteLine($"Loading image from {filename}");
  }
  public void Draw()
  {
    WriteLine($"Drawing image {filename}");
  }
}
The very act of construction of this Bitmap will trigger the loading of the image:
var img = new Bitmap("pokemon.png");
// Loading image from pokemon.png

That’s not quite what we want. What we want is the kind of bitmap that only loads itself when the Draw() method is used. Now, I suppose we could jump back into Bitmap and make it lazy, but we’re going to assume the original implementation is set in stone and is not modifiable.

So what we can then build is a virtual proxy that will use the original Bitmap, provide an identical interface, and also reuse the original Bitmap’s functionality:
class LazyBitmap : IImage
{
  private readonly string filename;
  private Bitmap bitmap;
  public LazyBitmap(string filename)
  {
    this.filename = filename;
  }
  public void Draw()
  {
    if (bitmap == null)
      bitmap = new Bitmap(filename);
    bitmap.Draw();
  }
}

Here we are. As you can see, the constructor of this LazyBitmap is a lot less “heavy”: all it does is store the name of the file to load the image from, and that’s it – the image doesn’t actually get loaded.1

All of the magic happens in Draw(): this is where we check the bitmap reference to see whether the underlying (eager!) bitmap has been constructed. If it hasn’t, we construct it and then call its Draw() function to actually draw the image.

Now imagine you have some API that uses an IImage type:
public static void DrawImage(IImage img)
{
  WriteLine("About to draw the image");
  img.Draw();
  WriteLine("Done drawing the image");
}
We can use that API with an instance of LazyBitmap instead of Bitmap (hooray, polymorphism!) to render the image, loading it in a lazy fashion:
var img = new LazyBitmap("pokemon.png");
DrawImage(img); // image loaded here
// About to draw the image
// Loading image from pokemon.png
// Drawing image pokemon.png
// Done drawing the image

Communication Proxy

Suppose you call a method Foo() on an object of type Bar. Your typical assumption is that Bar has been allocated on the same machine as the one running your code, and you similarly expect Bar.Foo() to execute in the same process.

Now imagine that you make a design decision to move Bar and all its members off to a different machine on the network. But you still want the old code to work! If you want to keep going as before, you’ll need a communication proxy – a component that proxies the calls “over the wire” and of course collects results, if necessary.

Let’s implement a simple ping-pong service to illustrate this. First, we define an interface:
interface IPingable
{
  string Ping(string message);
}
If we are building ping-pong in process, we can implement Pong as follows:
class Pong : IPingable
{
  public string Ping(string message)
  {
    return message + " pong";
  }
}

Basically, you ping a Pong and it appends the word "pong" to the end of the message and returns that message. Notice that I’m not using a StringBuilder here, but instead making a new string on each turn: this lack of mutation helps replicate this API as a web service.

We can now try out this setup and see how it works in-process:
void UseIt(IPingable pp)
{
  WriteLine(pp.ping("ping"));
}
Pong pp = new Pong();
for (int i = 0; i < 3; ++i)
{
  UseIt(pp);
}

And the end result is that we print “ping pong” three times, just as we wanted.

So now, suppose you decide to relocate the Pingable service to a web server, far-far away. Perhaps you even decide to expose it through a special framework such as ASP.NET:
[Route("api/[controller]")]
public class PingPongController : Controller
{
  [HttpGet("{msg}")]
  public string Get(string msg)
  {
    return msg + " pong";
  }
}
With this setup , we’ll build a communication proxy called RemotePong that will be used in place of Pong:
class RemotePong : IPingable
{
  string Ping(string message)
  {
    string uri = "http://localhost:9149/api/pingpong/" + message;
    return new WebClient().DownloadString(uri);
  }
}
With this implemented, we can now make a single change:
RemotePong pp; // was Pong
for (int i = 0; i < 3; ++i)
{
  UseIt(pp);
}

And that’s it, you get the same output, but the actual implementation can be running on Kestrel in a Docker container somewhere halfway around the world .

Dynamic Proxy for Logging

Say you’re testing a piece of code and you want to record the number of times particular methods are called, and what arguments they are called with. You have a couple of options, including
  • Using AOP approaches such as PostSharp or Fody to create assemblies where the required functionality is weaved into the code

  • Using profiling/tracing software instead

  • Creating dynamic proxies for your objects in tests

A dynamic proxy is a proxy created at runtime. It allows us to take an existing object and, provided a few rules are followed, to override or wrap some of its behaviors to perform additional operations.

So imagine that you are writing tests that cover the operation of a BankAccount, a class that implements the following interface:
public interface IBankAccount
{
  void Deposit(int amount);
  bool Withdraw(int amount);
}
Suppose that your starting point is a test such as the following:
var ba = new BankAccount();
ba.Deposit(100);
ba.Withdraw(50);
WriteLine(ba);

When performing those operations, you also want a count of the number of methods that have been called. So, effectively, you want to wrap a BankAccount with some sort of dynamically constructed proxy that implements the IBankAccount interface and keeps a log of all the methods called.

We shall construct a new class that we’ll call Log<T> that is going to be a dynamic proxy for any type T:
public class Log<T> : DynamicObject
  where T : class, new()
{
  private readonly T subject;
  private Dictionary<string, int> methodCallCount =
    new Dictionary<string, int>();
  protected Log(T subject)
  {
    this.subject = subject;
  }
}

Our class takes a subject, which is the class it’s wrapping, and has a simple dictionary of method call counts.

Now, the preceding class inherits from DynamicObject , which is great because we want to make a log of the calls made to its various methods, and only then actually invoke those methods. Here’s how we can implement this:
public override bool TryInvokeMember(
  InvokeMemberBinder binder, object[] args, out object result)
{
  try
  {
    if (methodCallCount.ContainsKey(binder.Name))
      methodCallCount[binder.Name]++;
    else
      methodCallCount.Add(binder.Name, 1);
    result = subject
      ?.GetType()
      ?.GetMethod(binder.Name)
      ?.Invoke(subject, args);
    return true;
  }
  catch
  {
    result = null;
    return false;
  }
}

As you can see, all we’re doing is logging the number of calls made to a particular method and then invoking the method itself using reflection.

Now, there’s only one tiny problem for us to handle: how do we get our Log<T> to pretend as if it were implementing some interface I? This is where dynamic proxy frameworks come in. The one we’re going to be using is called ImpromptuInterface .2 This framework has a method called ActLike() that allows a dynamic object to pretend that it is of a particular interface type.

Armed with this, we can give our Log<T> a static factory method that would construct a new instance of T, wrap it in a Log<T>, and then expose it as some interface I:
public static I As<I>() where I : class
{
  if (!typeof(I).IsInterface)
    throw new ArgumentException("I must be an interface type");
  // duck typing here!
  return new Log<T>(new T()).ActLike<I>();
}
The end result of it all is that we can now perform a simple replacement and get a record of all the calls made to the bank account class:
//var ba = new BankAccount();
var ba = Log<BankAccount>.As<IBankAccount>();
ba.Deposit(100);
ba.Withdraw(50);
WriteLine(ba);
// Deposit called 1 time(s)
// Withdraw called 1 time(s)

Naturally, in order for the preceding code to work, I’ve overridden Log<T>.ToString() to output call counts. Sadly, the wrapper we’ve made will not automatically proxy over calls to ToString()/Equals()/GetHashCode() because every object has them intrinsically built in. If you do want to connect these to the underlying, you’d have to add overrides in Log<T> and then use the subject field to make the appropriate calls.

Summary

This chapter has presented a number of proxies. Unlike the Decorator pattern, the Proxy doesn’t try to expand the public API surface of an object by adding new members (unless it can’t be helped). All it tries to do is enhance the underlying behavior of existing members.
  • Plenty of different proxies exist.

  • Property proxies are stand-in objects that can replace fields and perform additional operations during assignment and/or access.

  • Virtual proxies provide virtual access to the underlying object and can implement behaviors such as lazy object loading. You may feel like you’re working with a real object, but the underlying implementation may not have been created yet and can, for example, be loaded on demand.

  • Communication proxies allow us to change the physical location of the object (e.g., move it to the cloud) but allow us to use pretty much the same API. Of course, in this case the API is just a shim for a remote service such as some available REST API.

  • Logging proxies allow you to perform logging in addition to calling the underlying functions.

There are lots of other proxies out there, and chances are that the ones you build yourself will not fall into a preexisting category, but will instead perform some action specific to your domain.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.35.229