Archive

Posts Tagged ‘Object (computer science)’

Decorator Pattern in Java

Decorator Pattern

 

Motivation

Extending an object‘s functionality can be done statically (at compile time) by using inheritance however it might be necessary to extend an object’s functionality dynamically (at runtime) as an object is used.

Consider the typical example of a graphical window. To extend the functionality of the graphical window for example by adding a frame to the window, would require extending the window class to create a FramedWindow class. To create a framed window it is necessary to create an object of the FramedWindow class. However it would be impossible to start with a plain window and to extend its functionality at runtime to become a framed window.

 

Intent

  • The intent of this pattern is to add additional responsibilities dynamically to an object.

 

Implementation

The figure below shows a UML class diagram for the Decorator Pattern:
Decorator Pattern Implementation - UML Class Diagram The participants classes in the decorator pattern are:

  • Component – Interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent – Defines an object to which additional responsibilities can be added.
  • Decorator – Maintains a reference to a Component object and defines an interface that conforms to Component’s interface.
  • Concrete Decorators – Concrete Decorators extend the functionality of the component by adding state or adding behavior.

Description

The decorator pattern applies when there is a need to dynamically add as well as remove responsibilities to a class, and when subclassing would be impossible due to the large number of subclasses that could result.

 

Applicability & Examples

Example – Extending capabilities of a Graphical Window at runtime

Decorator Pattern Example - UML Class Diagram

In Graphical User Interface toolkits windows behaviors can be added dynamically by using the decorator design pattern.

Consequences

  • Decoration is more convenient for adding functionalities to objects instead of entire classes at runtime. With decoration it is also possible to remove the added functionalities dynamically.
  • Decoration adds functionality to objects at runtime which would make debugging system functionality harder.
Advertisements

Making your class compatible with Java hash maps: overriding hashCode() and equals()

If  you have prior knowledge of hashing, then you may have an idea of how to write the hash function itself. On this page we’ll discuss the nuts and bolts you need to actually plug your hash function into a Java class and therefore use instances of that class as a hash map key. (Note that we concentrate on HashMaps here, but the points we discuss generally hold for related classes such as ConcurrentHashMap and HashSet.)

The basics: override hashCode() and equals()

Put very simply, there are two methods that a class needs to override to make objects of that class work as hash map keys:

public int hashCode();
public boolean equals(Object o);

As you might expect, the hashCode() method is where we put our hash function. Note that HashMap will not do any extra caching of the hash code. So if calculating the hash is relatively expensive (as in the case of String) it may be worth explicitly caching the hash code.

The equals() method

The equals() method must return true if the fields of the current object equal those of the object passed in, else return false. By “equal”, we generally mean that primitive fields match via the == operator, and objects are either both null or both non-null and match via the equals() method. Note two important constraints on equals():

  • if x.equals(y) returns true, then the hash codes of x and y must be identical;
  • it must be reflexive and transitive: that is, x.equals(y) must return the same value as y.equals(x), and if x.equals(y) and y.equals(z), then x.equals(z) must also be true (see below for what this actually means in real terms!).

The first of these is generally common sense given that the purpose of a hash function is to “narrow down a search” which will ultimately be performed using the equals() to perform the final check for a match. The second is more or less common sense, but it does mean, for example, that we can’t allow a null reference to equal an “empty” object. It also means, strictly speaking, that a subclass cannot add new variable comparisons to the equals() method2.

Example

Now let’s see an example. We’ll look at a simple class that encapsulates a pair of screen coordinates. We assume that individually, the X and Y coordinates are essentially random, but that the maximum coordinate in each case will be in the order of a couple of thousand (in other words will have about 10 or 11 bits of randomness). So to make the hash code, we pick a number that is roughly halfway between these bits, then find a prime (or at worst odd) number that is close to 211. Our old favourite of 31 (=25-1) will do us fine. The equals() method is trivial, but note the convention of returning false if the object passed in isn’t of a compatible type.

public class CoordinatePair {
  private int x, y;
  public int hashCode() {
 return (x * 31) ^ y;
  }
  public boolean equals(Object o) {
    if (o instanceof CoordinatePair) {
      CoordinatePair other = (CoordinatePair) o;
      return (x == other.x && y == other.y);
    }
    return false;
  }
}

1. I think this convention predates Java 5 generics: arguably, we really don’t expect a case where equals() will be called against an object of an incompatible type and should just apply the case an rely on the resulting runtime exception if the cast fails.
2. The problem with subclassing can be explained with a quick example. Suppose we extend Rectangle (whose equals() method effectively compares its co-ordinates and dimensions, although via the Rectangle2D base class) to make a class called ColouredRectangle, whose equals() method returns true if and only if the colours of the rectangles are identical. Now we have the problem that a plain Rectangle, if passed a ColouredRectangle to its equals() method, would return true provided the co-ordinates and dimensions were the same, discounting the colour; whereas the other way round, ColouredRectangle.equals() would always return false (because it wasn’t comparing against another ColouredRectangle).

%d bloggers like this: