July 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Design Pattern: Proxy

  • August 1, 2007
  • By Jeff Langr
  • Send Email »
  • More Articles »

With the interface in place, I can start building the proxy. For now, I keep it simple, and define the proxy only to delegate to the real Portfolio.

import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;

public class PortfolioGuardTest {
   private Map<String, Integer> purchases;

   Portfolio target = new Portfolio() {
      @Override
      public int numberOfHoldings() {
         return 1;
      }

      @Override
      public void purchase(String symbol, int shares) {
         purchases.put(symbol, shares);
      }

      @Override
      public int sharesOf(String symbol) {
         if (symbol.equals("symbol")) return 1;
         return 0;
      }
   };

   @Before
   public void initialize() {
      purchases = new HashMap<String, Integer>();
   }

   @Test
   public void delegatesAllMethods() {
      boolean canUpdate = true;

      Portfolio portfolio = new PortfolioGuard(canUpdate, target);
      portfolio.purchase("symbol", 1);
      assertEquals(1, purchases.size());
      assertEquals(1, purchases.get("symbol"));
      assertEquals(1, portfolio.numberOfHoldings());
      assertEquals(1, portfolio.sharesOf("symbol"));
   }
}

Rather than use PortfolioImpl, I define a stub implementation of the Portfolio interface in PortfolioGuardTest. This implementation exists solely to track whether or not appropriate methods were called, as part of the delegatesAllMethods test.

The constructor of PortfolioGuard takes two arguments: a target instance of Portfolio, and a boolean indicating whether or not updates are allowed. For now, this flag is set to true. Here's the implementation of PortfolioGuard:

public class PortfolioGuard implements Portfolio {
   private final Portfolio target;
   private final boolean canUpdate;

   public PortfolioGuard(boolean canUpdate, Portfolio target) {
      this.canUpdate = canUpdate;
      this.target = target;
   }

   @Override
   public int numberOfHoldings() {
      return target.numberOfHoldings();
   }

   @Override
   public void purchase(String symbol, int shares) {
      target.purchase(symbol, shares);
   }

   @Override
   public int sharesOf(String symbol) {
      return target.sharesOf(symbol);
   }
}

In a second test, I set the "can update" flag to false, and then verify that calling the purchase method generates an exception.

@Test(expected=RuntimeException.class)
public void prohibitsMutatorMethodsWhenUpdateRestricted() {
   boolean canUpdate = false;
   Portfolio portfolio = new PortfolioGuard(canUpdate, target);
   portfolio.purchase("symbol", 1);
}

After demonstrating test failure, I add a couple lines to PortfolioGuard in order to get it to pass:

@Override
public void purchase(String symbol, int shares) {
   if (!canUpdate)
      throw new RuntimeException();
   target.purchase(symbol, shares);
}

The final piece of the puzzle is to make sure that clients interact with a PortfolioGuard instance and not a real PortfolioImpl instance. I can do that by introducing a factory and telling client developers to use the factory to obtain Portfolio objects.

import static org.junit.Assert.*;
import org.junit.*;

public class PortfolioFactoryTest {
   @Test
   public void createWithUpdateAccess() {
      User user = User.create("x");
      Portfolio portfolio = PortfolioFactory.create(user);
      portfolio.purchase("x", 1);
      assertEquals(1, portfolio.numberOfHoldings());
   }

   @Test(expected=RuntimeException.class)
   public void createWithReadOnlyAccess() {
      User user = User.createReadOnly("x");
      Portfolio portfolio = PortfolioFactory.create(user);
      portfolio.purchase("x", 1);
   }
}




Page 2 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel