Java Reference
In-Depth Information
}
public void print(Document d, int nrCopies, boolean printDuplicate) {
printer.print(d, nrCopies, printDuplicate);
}
}
Note how this class reimplements all the methods from the original Printer interface and passes on
every command to the contained Printer instance (again, this is an example of the adapter pattern).
Instead of using the Printer interface in your client code, you now use AbstractPrintSpooler ,
however. Note that you can also decide to have AbstractPrintSpooler implement the Printer
interface (this forces the abstraction to also implement all methods from the implementation) and to
make the class nonabstract if you want to use it as is (which is also perfectly valid). All things con-
sidered, it does seem that the AbstractPrintSpooler class is adding nothing of value, so then why
would you add another layer of abstraction? The reason is that you can now add concrete subclasses
of this abstraction. Imagine for example a GreenPrintSpooler like so:
public class GreenPrintSpooler extends AbstractPrintSpooler {
public GreenPrintSpooler(Printer printer) {
super(printer);
}
public void print(Document d, int nrCopies, boolean printDuplicate) {
printDuplicate = true; // Force to print duplicates
d.setToBlackAndWhite(); // Convert document to black and white
print(d, nrCopies, printDuplicate);
}
}
A concrete implementation of your spooler has now been created that will convert all documents to
black and white and force the duplicate option to true before passing on the print command to the
implementation. The benefits of this pattern should become clear to you now: bridges are helpful
whenever an extra layer of abstraction is needed on top of something else. For example, whether to
print green is a separate decision on top of the printer model being used.
Decorator Pattern
The decorator pattern also bears similarities to the adapter pattern. It allows you to add behavior
to a single instance of a class without adding this behavior to all instances of the same class (as you
would end up with through normal subclassing).
This pattern is commonly used in GUI programming, so it makes sense to include an example from
this context. Imagine you have created a Window class to display fancy GUI windows. Now let's say
you want to create a particular variant of these windows that cannot be minimized and needs to
stay on-screen. You can simply create a NaggingWindow class that extends the Window class and adds
behavior to disable the minimize button. Imagine that, sometime later, you also encounter a need to
add scrollbars to some of your windows. No problem, as you can just create a ScrollableWindow
class to do this. However, what about windows that should not be minimized and also need
scrollbars? One solution might be to add a NaggingScrollableWindow class, but as windows get
more and more features, this would quickly lead to a soup of redundant subclasses. One solution is
to merge everything in the single Window class, but this would lead to a single, horribly confusing
 
Search WWH ::




Custom Search