Working With Design Patterns: Odds and Ends
A specification implementation provides the selection criteria in the isSatisfiedBy method:
public class AuthorSpecification implements Specification { private final String author; public AuthorSpecification(String author) { this.author = author; } @Override public boolean isSatisfiedBy(Holding holding) { return author.equals(holding.getBook().getAuthor()); } }
Here's another specification implementation that supports selecting by matching book title:
public class TitleSpecification implements Specification { private final String title; public TitleSpecification(String title) { this.title = title; } @Override public boolean isSatisfiedBy(Holding holding) { return title.equals(holding.getBook().getTitle()); } }
You conceivably could eliminate a bit of redundancy by factoring construction of both of these specifications into a common superclass.
With the specification classes in place, the code in HoldingsAccess simplifies. The single method findBy covers any specification passed to it:
public List<Holding> findBy(Specification specification) { List<Holding> results = new ArrayList<Holding>(); for (Holding holding: getAll()) if (specification.isSatisfiedBy(holding)) results.add(holding); return results; }
The HoldingsAccess class is now closed to changes in Holding—adding a new Holding field now requires adding a new Specification implementation. The elimination of impact to HoldingsAccess meets the open-closed principle: Modules should be closed for modification, but open to extension.
Lazy Initialization
Lazy initialization means that you defer initializing a field to a useful value until the time it's first needed. It is a performance optimization.
A library system search returns a list of Book objects. The system presents the user with a list displaying basic book information—author, title, year published, and so on. When the user selects a book for further information, the system shows an image of the front cover of the book. Listing 2 shows an implementation of a Book class that handles loading an image upon construction.
Listing 2: Book.
import java.awt.image.*; import java.io.*; import javax.imageio.*; public class Book { private final String author; private final String title; private final String classification; private final String year; private BufferedImage coverImage; public Book(String author, String title, String classification, String year, String imageFilename) { this.author = author; this.title = title; this.classification = classification; this.year = year; loadCoverImage(imageFilename); } public String getClassification() { return classification; } public String getAuthor() { return author; } public String getTitle() { return title; } public String getYear() { return year; } @Override public String toString() { return author + " " + title + " " + year + " " + classification; } public BufferedImage getCoverImage() { return coverImage; } private void loadCoverImage(String imageFilename) { try { coverImage = ImageIO.read(new File(imageFilename)); } catch (IOException e) { throw new RuntimeException(e); } } }
Page 2 of 4
This article was originally published on September 18, 2008