03.

advertisement
1) Adapter (Structural Design Pattern)
http://java.dzone.com/articles/design-patterns-uncovered-0
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that
couldn't otherwise because of incompatible interfaces.
Consider that we have a third party library that provides sorting functionality through it's NumberSorter class. This is
our Adaptee. Our Client deals with primitive arrays rather than Lists. For the sake of this example, lets say we can't
change the client to use Lists. We've provided a Sorter interface that expects the client input. This is our target.
Finally, the SortListAdapter implements our target interface and deals with our adaptee, NumberSorter.
/*Adaptee*/
01./*
02.* This is our adaptee, a third party implementation of a
03.* number sorter that deals with Lists, not arrays.
04.*/
05.public class NumberSorter
06.{
07.public List<Integer> sort(List<Integer> numbers)
08.{
09.//sort and return
10.return new ArrayList<Integer>();
11.}
12.
13.}
1
/*Client*/
1.int[] numbers = new int[]{34, 2, 4, 12, 1};
2.
3.Sorter sorter = new SortListAdapter();
4.sorter.sort(numbers);
/*Target Interface*/
1.//this is our Target interface
2.public interface Sorter
3.{
4.public int[] sort(int[] numbers);
5.}
/*Adapter*/
01.public class SortListAdapter implements Sorter
02.{
03.
04.@Override
05.public int[] sort(int[] numbers)
06.{
07.//convert the array to a List
08.List<Integer> numberList = new ArrayList<Integer>();
09.
10.//call the adapter
11.NumberSorter sorter = new NumberSorter();
12.numberList = sorter.sort(numberList);
13.
14.//convert the list back to an array and return
15.
16.return sortedNumbers;
17.}
18.
19.}
2) Facade (Structural Design Pattern)
http://java.dzone.com/articles/design-patterns-uncovered-1
Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that
makes the subsystem easier to use.
2
Let's take a travel agent site for example, that allows you to book hotels and flights. We have a HotelBooker: Both of
these have Hotel and Flight datatypes, which the client has knowledge about. They could be provided in the same
package as the Facade for example. The TravelFacade class allows the user to get their Hotel and Flight information
in one call:
01.public class HotelBooker /*Package1 Class1*/
02.{
03.
04.public ArrayList<Hotel> getHotelNamesFor(Date from, Date to)
05.{
06.//returns hotels available in the particular date range
07.
08.}
09.
10.}
01.public class FlightBooker /*Package2 Class1*/
02.{
03.
04.public ArrayList<Flight> getFlightsFor(Date from, Date to)
05.{
06.//returns flights available in the particular date range
07.
08.}
09.
10.}
01.public class TravelFacade
02.{
03.
04.private HotelBooker hotelBooker;
05.private FlightBooker flightBooker;
06.
07.public void getFlightsAndHotels(Date from, Data to)
08.{
09.ArrayList<Flight> flights = flightBooker.getFlightsFor(from, to);
10.ArrayList<Hotel> hotels = hotelBooker.getHotelsFor(from, to);
11.
12.//process and return
13.
14.}
15.
16.}
01.public class Client
3
02.{
03.
04.public static void main(String[] args)
05.{
06.TravelFacade facade = new TravelFacade();
07.facade.getFlightsAndHotels(from, to);
08.}
09.}
4
3) Singleton (Creational Design Pattern)
http://java.dzone.com/articles/design-patterns-singleton
Ensure a class has only one instance and provide a global point of access to it.
When you need to ensure there's one instance of an object, available to a number of other classes, you may want
to use the Singleton pattern. Singletons are used a lot where you need to provide a registry, or something like a
thread pool. Logging is also another popular use of Singletons, providing one single access point to an applications
log file. This example will show how to put together the classic Singleton in Java, without thinking about the
threading complications which we discuss later on in this article. The Singleton class has some characteristics that
we generally want to ensure two things:

We lazily load our singleton based on the first request for access to it.

There is no other way of instantiating our Singleton
/*Singleton*/
01.public class Singleton
02.{
03.private Singleton instance;
04.
05.private Singleton()
06.{
07.}
08.
09.public static Singleton getInstance()
10.{
11.if(instance==null)
12.{
13.instance = new Singleton();
14.}
15.return instance;
16.}
17.
18.
19.}
/*Client*/
1.//access the singleton
2.Singleton singleton = Singleton.getInstance();
3.//use the singleton
5
4) Factory Method (Creational Design Pattern)
http://java.dzone.com/articles/design-patterns-factory
Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method
lets a class defer instantiation to subclasses
Now, let's take a look at the diagram definition of the Factory Method pattern. The Creator hides the creation and
instantiation of the Product from the client. This is a benefit to the client as they are now insulated from any future
changes - the Creator will look after all of their creation needs, allowing to decoupling. Furthermore, once the Creator
and the Product conform to an interface that the client knows, the client doesn't need to know about the concrete
implementations of either. The factory method pattern really encourages coding to an interface in order to deal with
future change.
Here the Creator provides an interface for the creation of objects, known as the factory method. All other methods in
our abstract Creator are written only to operate on the Products created in theConcreteCreator. The Creator doesn't
create the products - that work is done by it's subclasses, such as ConcreateCreator.
The idea behind the Factory Method pattern is that it allows for the case where a client doesn't
know what concrete classes it will be required to create at runtime, but just wants to get a class
that will do the job. The FactoryMethod builds on the concept of a simple Factory, but lets the
subclasses decide which implementation of the concrete class to use. You'll see factories used in
logging frameworks, and in a lot of scenarios where the client doesn't need to know about the
concrete implementations. It's a good approach to encapsulation.This example will use the
concept of a logger to illustrate the factory method. First, let's create our Product interface, in this
case Logger:
6
1.//interface (Product)
2.public interface Logger {
3.
4.public void log(String message);
5.}
01.//concrete implementation of the Logger (Concrete Product)
02.public class XMLLogger implements Logger {
03.
04.public void log(String message) {
05.//log to xml
06.System.err.println("logging");
07.}
08.
09.}
01.//the abstract Creator
02.public abstract class AbstractLoggerCreator
03.{
04.//the factory method
05.public abstract Logger createLogger();
06.
07.
08.//the operations that are implemented for all LoggerCreators
09.//like anOperation() in our diagram
10.public Logger getLogger()
11.{
12.//depending on the subclass, we'll get a particular logger.
13.Logger logger = createLogger();
14.
15.//could do other operations on the logger here
16.
17.return logger;
18.}
19.
20.}
01.//ConcreteCreator
02.public class XMLLoggerCreator extends AbstractLoggerCreator{
03.
04.@Override
05.public Logger createLogger() {
06.XMLLogger logger = new XMLLogger();
07.return logger;
08.}
09.
10.}
7
01.public class Client {
02.private void someMethodThatLogs(AbstractLoggerCreator logCreator)
03.{
04.Logger logger = logCreator.createLogger();
05.logger.log("message");
06.
07.}
08.
09.
10.
11.public static void main(String[] args)
12.{
13.//for the purposes of this example, create an XMLLoggerCreator directly,
14.//but this would normally be passed to constructor for use.
15.AbstractLoggerCreator creator = new XMLLoggerCreator();
16.
17.Client client = new Client();
18.client.someMethodThatLogs(creator);
19.}
20.
21.}
5) Observer (Behavioral Design Pattern)
http://java.dzone.com/articles/design-patterns-uncovered
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are
notified and updated automatically.
Before we get into the theory and code behind the Observer, let's take a look at a real world example, such as RSS
feeds. When I want to get updates from a particular feed, I add it to my feed reader. Any time that the RSS feed has
an update, it will appear in my reader automatically. This is the Observer pattern in action, a publisher/subscriber
relationship with one source having many subscribers.
The idea behind the pattern is simple - one of more Observers are interested in the state of aSubject and register
their interest with the Subject by attaching themselves. When something changes in our Subject that the Observer
may be interested in, a notify message is sent, which calls the update method in each Observer.
When the Observer is no longer interested in the Subject's state, they can simply detatchthemselves.
8
In our example, the subject will be a DataStore, with a Screen class as the observer.First, let's make our DataStore
class observable by extending the java.util.Observable class. This means that our DataStore has all the methods
and functionality available to make it a Subject, according to our pattern.
01.import java.util.Observable;
02.
03.public class DataStore extends Observable
04.{
05.
06.private String data;
07.
08.public String getData()
09.{
10.return data;
11.}
12.
13.public void setData(String data)
14.{
15.this.data =data;
16.//mark the observable as changed
9
17.setChanged();
18.}
19.}
01.public class Screen implements Observer {
02.
03.@Override
04.public void update(Observable o, Object arg) {
05.
06.//act on the update
07.}
08.
09.}
1.Screen screen = new Screen();
2.
3.DataStore dataStore = new DataStore();
4.//register observer
5.dataStore.addObserver(screen);
6.
1.//send a notification
2.dataStore.notifyObservers();
10
6) Strategy (Behavioral Design Pattern)
http://java.dzone.com/articles/design-patterns-strategy
Defines a set of encapsulated algorithms that can be swapped to carry out a specific behaviour
In the diagram Context is composed of a Strategy. The context could be anything that would require changing
behaviours - a class that provides sorting functionality perhaps. The Strategy is simply implemented as an interface,
so that we can swap ConcreteStrategys in and out without effecting our Context
The Strategy pattern is to be used where you want to choose the algorithm to use at runtime. A good use of the
Strategy pattern would be saving files in different formats, running various sorting algorithms, or file compression. The
Strategy pattern provides a way to define a family of algorithms, encapsulate each one as an object, and make them
interchangeable. Let's use the example of a file compression tool - where we create either zip or rar files. First we'll
need a strategy:
11
1.//Strategy Interface
2.public interface CompressionStrategy
3.{
4.public void compressFiles(ArrayList<File> files);
5.}
01.public class ZipCompressionStrategy implements CompressionStrategy
02.{
03.
04.public void compressFiles(ArrayList<File> files)
05.{
06.//using ZIP approach
07.}
08.
09.}
01.public class RarCompressionStrategy implements CompressionStrategy
02.{
03.
04.public void compressFiles(ArrayList<File> files)
05.{
06.//using RAR approach
07.}
08.
09.}
01.public class CompressionContext
02.{
03.private CompressionStrategy strategy;
04.
05.//this can be set at runtime by the application preferences
06.public void setCompressionStrategy(CompressionStrategy strategy)
07.{
08.this.strategy = strategy;
09.}
10.
11.//use the strategy
12.public void createArchive(ArrayList<File> files)
13.{
14.strategy.compressFiles(files);
15.}
16.
17.}
01.public class Client
02.{
03.
04.public static void main(String[] args)
05.{
06.CompressionContext ctx = new CompressionContext();
07.//we could assume context is already set by preferences
08.ctx.setCompressionStrategy(new ZipCompressionStrategy());
09.//get a list of files
10....
11.ctx.createArchive(fileList);
12.
13.}
14.}
12
7) Composite (Structural Design Pattern)
http://java.dzone.com/articles/design-patterns-composite
Allow you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat
individual objects and compositions of objects uniformly.
The Component interface defines the interface that all objects in the composed system need to use, whether they are
leafs (simple objects) or compositions. However, this is usually implemented as an abstract class providing some
default behaviour for the add, remove and getChild methods.
The Leaf has no children, and as such only needs to implement the operation method. TheComposite needs to do
more, as it also contains components. The composite will more than likely need to implement the operation method,
which is considered as a Leaf-related operation. Sometimes this may not make sense for a composite to implement.
Usually, the Composite will implement methods by delegating to the children. The Client simply uses the Component
interface to manipulate the objects.
This pattern should be used when you want to represent objects in a hierachical fashion, or you need objects and
composites to be treated uniformly.
Graphics frameworks are the most common use of this pattern. The base Graphic object provides the base class for
all other graphic objects, such as Line, Rectangle, which provide their own implementations of the pGraphics is a
great example of how the Composite pattern works, so I'll use that here. First, we create an general interface for our
graphics object. The main thing is that we have a paint method. Each graphic could be composed of other graphics
too, so we'll need to provide a way to contain these objects. paint()/draw() method. The Composite pattern is
frequently used for abstract syntax tree representations.
Graphics is a great example of how the Composite pattern works, so I'll use that here. First, we create an
general interface for our graphics object. The main thing is that we have a paint method. Each graphic
could be composed of other graphics too, so we'll need to provide a way to contain these objects.
13
1.//Component interface
2.public interface Graphic
3.{
4.public void add(Graphic g);
5.public void remove(Graphic g);
6.public Graphic get(int index);
7.public void paint();
8.}
01.//Composite
02.public class CompositeGraphic implements Graphic
03.{
04.private List<Graphic> children = new ArrayList<Graphic>();
05.
06.public void paint()
07.{
08.//run the paint operation for each child
09.for(Graphic g: children)
10.{
11.g.paint();
12.}
13.}
14.
15.
16.public void add(Graphic g)
17.{
18.children.add(g);
19.}
20.
21.public void remove(Graphic g)
22.{
23.if(children.contains(g))
24.{
25.children.remove(g);
26.}
27.}
28.
29.public Graphic get(int index)
30.{
31.if(index < children.size())
32.{
33.return children.get(index);
34.}
35.}
36.
37.
38.}
01.//Leaf
02.public class SimpleGraphic implements Graphic
03.{
04.
05.public void paint()
06.{
07.//run the paint operation
08.}
09.
10./**
11.* Because we have no children, these operations will do nothing
12.**/
14
13.public void add(Graphic g)
14.{
15.//unsupported operation
16.}
17.
18.public void remove(Graphic g)
19.{
20.//unsupported operation
21.}
22.
23.public void get(int index)
24.{
25.//unsupported operation
26.}
27.}
01.//Client.
02.public class GraphicsClient
03.{
04./**
05.* Given a graphics context, client can just call paint, without worrying if this is a composite or leaf
06.**/
07.public void paint(Graphics g)
08.{
09.g.paint();
10.}
11.}
15
8) Abstract Factory (Creational Design Pattern)
http://java.dzone.com/articles/design-patterns-abstract-factory
Provides an interface for creating families of related or dependent objects without specifying their
concrete classes.
The AbstractFactory defines the interface that all of the concrete factories will need to implement
in order to product Products. ConcreteFactoryA and ConcreteFactoryB have both implemented
this interface here, creating two seperate families of product.
Meanwhile, AbstractProductA andAbstractProductB are interfaces for the different types of
product. Each factory will create one of each of these AbstractProducts.
The Client deals with AbstractFactory, AbstractProductA and AbstractProductB. It doesn't
know anything about the implementations. The actual implementation of AbstractFactory that
the Clientuses is determined at runtime.
As you can see, one of the main benefits of this pattern is that the client is totally decoupled from
the concrete products. Also, new product families can be easily added into the system, by just
adding in a new type of ConcreteFactory that implements AbstractFactory, and creating the
specific Product implementations.
16
The pattern is best utilised when your system has to create multiple families of products or you
want to provide a library of products without exposing the implementation details. As you'll have
noticed, a key characteristic is that the pattern will decouple the concrete classes from the client.
An example of an Abstract Factory in use could be UI toolkits. Across Windows, Mac and Linux, UI
composites such as windows, buttons and textfields are all provided in a widget API like SWT.
However, the implementation of these widgets vary across platforms. You could write a platform
independent client thanks to the Abstract Factory implementation.
17
1.//Our AbstractProduct
2.public interface Window
3.{
4.
5.public void setTitle(String text);
6.
7.public void repaint();
8.}
01.//ConcreteProductA1
02.public class MSWindow implements Window
03.{
04.public void setTitle()
05.{
06.//MS Windows specific behaviour
07.}
08.
09.public void repaint()
10.{
11.//MS Windows specific behaviour
12.}
13.}
01.//ConcreteProductA2
02.public class MacOSXWindow implements Window
03.{
04.public void setTitle()
05.{
06.//Mac OSX specific behaviour
07.}
08.
09.public void repaint()
10.{
11.//Mac OSX specific behaviour
12.}
13.}
1.//AbstractFactory
2.public interface AbstractWidgetFactory
3.{
4.public Window createWindow();
5.}
01.//ConcreteFactory1
02.public class MsWindowsWidgetFactory
03.{
04.//create an MSWindow
05.public Window createWindow()
06.{
07.MSWindow window = new MSWindow();
18
08.return window;
09.}
10.}
01.//ConcreteFactory2
02.public class MacOSXWidgetFactory
03.{
04.//create a MacOSXWindow
05.public Window createWindow()
06.{
07.MacOSXWindow window = new MacOSXWindow();
08.return window;
09.}
10.}
01.//Client
02.public class GUIBuilder
03.{
04.public void buildWindow(AbstractWidgetFactory widgetFactory)
05.{
06.Window window = widgetFactory.createWindow();
07.window.setTitle("New Window");
08.}
09.}
01.public class Main{
02.public static void main(String[] args)
03.{
04.GUIBuilder builder = new GUIBuilder();
05.AbstractWidgetFactory widgetFactory = null;
06.//check what platform we're on
07.if(Platform.currentPlatform()=="MACOSX")
08.{
09.widgetFactory = new MacOSXWidgetFactory();
10.}
11.else
12.{
13.widgetFactory = new MsWindowsWidgetFactory();
14.}
15.builder.buildWindow(widgetFactory);
16.}
17.}
19
Download