The essence of a pattern is a reusable solution for a recurring problem. A complete pattern will also provide reasons to use or not use the solution, the consequences of using the solution, and suggestions on how to implement the solution. The summaries in these articles will just describe the essential problem and its solution.
The first few patterns that I will be summarizing fall into a category that I call Fundamental Patterns. They are fundamental in the sense that they are widely used by other patterns or are frequently used in a large number of programs.
A common problem is that you want an object to be able to use another object that provides a service without having to assume the class of the other object. The usual solution to the problem is to have the object assume that the object it uses implements a particular interface, rather than it being an instance of any particular class.
For example, suppose you are writing an application to purchase goods for a business. Your program will need to be informed of such entities as vendors, freight companies, receiving locations, and billing locations. One thing these have in common is that they all have a street address. These street addresses will appear in different parts of the user interface. You will want to have a class for displaying and editing street addresses so that you can reuse it wherever there is an address in the user interface. We will call that class AddressPanel.
You want AddressPanel objects to be able to get and set address information in a separate data object. This raises the question of what instances of the AddressPanel class can assume about the class of the data objects that they will use. Clearly, you will use different classes to represent vendors, freight companies and the like. If you program in a language that supports multiple inheritance, like C++, you can arrange for the data objects that instances of AddressPanel use to inherit from an address class in addition to the other classes they inherit from. If you program in a language like Java that uses a single inheritance object model, then you must explore other solutions.
You can solve the problem by creating an address interface. Instances of the AddressPanel class would then simply require data objects that implement the address interface. They would then be able to call the accessor methods of that object to get and set its address information. Using the indirection that the interface provides, instances of the AddressPanel class are able to call the methods of the data object without having to be aware of what class it belongs to. Here is a class diagram showing these relationships:
Figure 1: Indirection through address interface.
In situations where multiple objects share access to the same object, problems can arise if changes to the shared object are not properly coordinated between objects that share it. Coordinating changes to an object can require careful programming that is easy to get wrong. If the changes to and fetches of the shared objects’ state are done asynchronously, then in addition to the greater likelihood of bugs, correctly functioning code will have the overhead of synchronizing the accesses to the shared objects’ state.
The Immutable pattern avoids these problems. It organizes a class so that the state information of its instances never changes after they are constructed.
Suppose that you are writing a game program that involves the placement and occasional movement of objects on a playing field. In the course of designing the classes for that program, you decide that you want to use immutable objects to represent the position of objects on the playing field. The organization of a class for modeling position that way might look like this:
Figure 2: Immutable position.
The position that a Position object represents is passed into its constructor. The Position class has methods to get the x and y value of the position its instances prepresent. It deliberately does not have any methods to change the x or y value of the position that a Position object represents. To represent a new position of a game piece, you create a new Position object.
A very commonly used class from the core Java API that is immutable is java.lang.String.
Though the Immutable pattern is not used by a lot of other patterns, it is fundamental in the sense that it is used extensively in the APIs that come with Java. It also turns up in a lot of programs.
Proxy is a pattern that occurs in a number of forms. The type of problem that it is intended to solve is the need to manage access to an object that provides a servce in a way that is transpartent to objects that use the service.
A proxy object is an object that receives method calls on behalf of another object. Client objects call the proxy object’s method. The proxy object’s methods do not directly provide the service that its clients expect. Instead, the proxy object’s methods call the methods of the actual object that provides the service. Here is a diagram showing that structure:
Figure 3: Method calls through a proxy.
Though a proxy object’s methods do not directly provide the service its clients expect, the proxy object manages access to those services. Proxy objects generally share a common interface with the service-providing object. Whether client objects directly access a service providing object or a proxy, they access it through the common interface, rather than as an instance of a particular class. This allows client objects to be unaware that they are calling the methods of a proxy object rather than the methods of the actual service-providing object.
Figure 4: Proxy class diagram.
There are many different types of access management that a proxy can be used to provide. Some of the more important ones will be described in future articles as patterns in their own right. Here are some of the more common uses for proxies:
- Make a method that can take a long time to complete appear to return immediately.
- Create the illusion that an object that exists on a different machine is an ordinary local object. This kind of proxy is called a remote proxy. It is used by RMI, CORBA, and other object request brokers.
- Control access to a service-providing object based on a security policy. This use of proxy is the Protection Proxy pattern.
- Create the illusion that a service object exists before it actually does. This can be useful if a service object is expensive to create and its services may not be needed. This use of proxies is the Virtual Proxy pattern.
About the author
Mark Grand is the author of a series of books titled Patterns in Java. He is currently the chief architect of an application framework for e-commerce called EBox. Mark Grand can be contacted at [email protected].