Saturday, January 14
A design pattern is a general solution to a common problem in software design. The idea is that the solution gets translated into code, and that the code can be applied in different situations where the problem occurs. Discussion of design patterns started with the book Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. These four authors are known as the "Gang of Four" or simply "GoF". In their book, the GoF categorized patterns into different subject areas, of which there are three primary areas: creational, structural, and behavioral. Creational patterns describe how objects are created (or "instantiated" in object-oriented terminology). Structural patterns offer help in how to connect and combine objects. Behavioral patterns describe algorithms or communication mechanisms. Some common pattern names are Singleton in the creational area, Observer in the behavioral area, and Facade in the structural area. This Tech Tip describes the Singleton pattern strictly in the context of the Java programming language. One of the commonly used creational patterns is the Singleton pattern. It describes a technique for ensuring that only a single instance of a class is ever created. In essence, the technique takes the following approach: don't let anyone outside the class create instances of the object. Typically, Singletons are lazily created to reduce memory requirements until needed. You can implement this approach in many different ways. If you know the one instance being created will be a subclass, make the parent class abstract and provide a method to get the current instance. An example of this is the Toolkit class in the AWT package. The constructor for Toolkit is public (the default constructor in this particular case): public Toolkit() and the class has a getDefaultToolkit() method for getting the specific subclass -- in this case, the subclass is platform-specific: public static Toolkit getDefaultToolkit() On a Linux platform with the Sun Java runtime, the specific subclass is of type sun.awt.X11.XToolkit. However you don't need to know that because you only access the class through its common abstract parent class, Toolkit. The Collator class is another example of this pattern, with a slight difference. It offers two getInstance() methods. The no-argument version gets the Collator for the default locale. You can pass in your own locale to get the instance of the Collator for that locale. Request the Collator for the same locale multiple times and you get back the same Collator instance. The constructor itself is protected. Similar ways of restricting class creation can be found throughout the J2SE standard libraries. At this point you might think that restricting access to the constructor of a class automatically makes it a Singleton. It doesn't. A case in point is the Calendar class. The Calendar class constructor is protected, and the class offers a getInstance() method to get an instance of the class. However, each call to getInstance() gets a new instance of the class. So that isn't a Singleton.A Singleton pattern is often used with another pattern called the Factory pattern. Like the Singleton pattern, the Factory pattern is a creational pattern. It describes how subclasses of a particular object, or more typically, implementers of a particular interface, do the actual object creation. A good example of the Factory pattern is the Swing BorderFactory class. The class has a series of static methods returning different types of Border objects. It hides the implementation details of the subclasses, allowing the factory to directly call the constructors for the interface implementations. Here's an example of BorderFactory in use: Border line = BorderFactory.createLineBorder(Color.RED); JLabel label = new JLabel("Red Line"); label.setBorder(line);Here, the fact that BorderFactory creates a LineBorder, or how BorderFactory does that, is hidden from the developer. In this particular example, you can directly call the LineBorder constructor, but in many cases of using the Factory pattern, you can't.Frequently, the class implementing the Singleton pattern returns an object to use as a Factory to create instances of a different class. This is exemplified by the PopupFactory class in the way it creates Popup objects. To get the Singleton factory, you call the getSharedInstance() method of PopupFactory: PopupFactory factory = PopupFactory.getSharedInstance();Then you create a Popup object from the factory by calling the factory's getPopup() method, passing in the parent component, its contents, and position: Popup popup = factory.getPopup(owner, contents, x, y);You'll find the Factory pattern used frequently in a security context. In the following example, a certificate factory is obtained for a particular algorithm, then a certificate for a stream is generated: FileInputStream fis = new FileInputStream(filename); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Collection c = cf.generateCertificates(fis);As shown with BorderFactory, the Factory pattern does not have to be used with the Singleton pattern. However the two patterns are frequently used together.