Design Pattern

  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Design Pattern as PDF for free.

More details

  • Words: 16,167
  • Pages: 90
Creational Patterns:::: Abstract Factory Definition Provides one level of interface higher than the factory pattern. It is used to return one of several factories.

Where to use & benefits • • • • • • • •

Creates families of related or dependent objects like Kit. Provides a class library of products, exposing interface not implementation. Needs to isolate concrete classes from their super classes. A system needs independent of how its products are created, composed, and represented. Try to enforce a constraint. An alternative to Facade to hide platform-specific classes Easily extensible to a system or a family Related patterns include o Factory method, which is often implemented with an abstract factory. o Singleton, which is often implemented with an abstract factory. o Prototype, which is often implemented with an abstract factory. o Facade, which is often used with an abstract factory by providing an interface for creating implementing class.

Example Suppose you need to write a program to show data in two different places. Let's say from a local or a remote database. You need to make a connection to a database before working on the data. In this case, you have two choices, local or remote. You may use abstract factory design pattern to design the interface in the following way:

class DataInfo {} interface Local {

}

DataInfo[] loadDB(String filename);

interface Remote extends Local{ void connect2WWW(String url); } class LocalMode implements Local { public DataInfo[] loadDB(String name) { System.out.print("Load from a local database "); return null; } } class RemoteMode implements Remote { public void connect2WWW(String url) { System.out.println("Connect to a remote site "); } public DataInfo[] loadDB(String name) { System.out.println("Load from a remote database "); return null; } } // The Abstract Factory interface ConnectionFactory { Local getLocalConnection(); Remote getRemoteConnection(); } class DataManager implements ConnectionFactory { boolean local = false; DataInfo[] data; //... public Local getLocalConnection() { return new LocalMode(); } public Remote getRemoteConnection() { return new RemoteMode(); } public void loadData() { if(local){ Local conn = getLocalConnection(); data = conn.loadDB("db.db"); }else { Remote conn = getRemoteConnection(); conn.connect2WWW("www.some.where.com"); data = conn.loadDB("db.db"); } }

// work on data

public void setConnection(boolean b) { local = b; } }

//Use the following Test class to test the above classes class Test { public static void main(String[] args) { DataManager dm = new DataManager(); DataInfo[] di = null; String dbFileName = "db.db"; if (args.length == 1) { //assume local is set to true dm.setConnection(true); LocalMode lm = (LocalMode)dm.getLocalConnection(); di = lm.loadDB(dbFileName); } else { //Note: dm.local = false is default setting RemoteMode rm = (RemoteMode)dm.getRemoteConnection(); rm.connect2WWW("www.javacamp.org/db/"); di = rm.loadDB(dbFileName); } //use one set of methods to deal with loaded data. //You don't need to worry about connection from this point. //Like di.find(), di.search() etc. } }

C:\

Command Prompt C:\> java Test Connect to a remote site Load from a remote database

C:\

Command Prompt C:\> java Test local Load from a local database

Such design is often used in SCJD project assignment. If you have a multiple places to load data, you just add more methods in the connection interface without altering other structure, or add a location variable in.

Factory Method Definition Provides an abstraction or an interface and lets subclass or implementing classes decide which class or method should be instantiated or called, based on the conditions or parameters given.

Where to use & benefits • •

Connect parallel class hierarchies. A class wants its subclasses to specify the object.

• • • • • • • • •

A class cannot anticipate its subclasses, which must be created. A family of objects needs to be separated by using shared interface. The code needs to deal with interface, not implemented classes. Hide concrete classes from the client. Factory methods can be parameterized. The returned object may be either abstract or concrete object. Providing hooks for subclasses is more flexible than creating objects directly. Follow naming conventions to help other developers to recognize the code structure. Related patterns include o Abstract Factory , which is a layer higher than a factory method. o Template method, which defines a skeleton of an algorithm to defer some steps to subclasses or avoid subclasses o Prototype, which creates a new object by copying an instance, so it reduces subclasses. o Singleton, which makes a returned factory method unique.

Examples To illustrate such concept, let's use a simple example. To paint a picture, you may need several steps. A shape is an interface. Several implementing classes may be designed in the following way. interface Shape { public void draw(); } class Line implements Shape { Point x, y; Line(Point a, Point b) { x = a; y = b; } public void draw() { //draw a line; } } class Square implements Shape { Point start; int width, height; Square(Point s, int w, int h) { start = s; width = w; height = h; } public void draw() { //draw a square; } } class Circle implements Shape { .... }

class Painting { Point x, y; int width, height, radius; Painting(Point a, Point b, int w, int h, int r) { x = a; y = b; width = w; height = h; radius = r; } Shape drawLine() { return new Line(x,y); } Shape drawSquare() { return new Square(x, width, height); } Shape drawCircle() { return new Circle(x, radius); } .... } ... Shape pic; Painting pt; //initializing pt .... if (line) pic = pt.drawLine(); if (square) pic = pt.drawSquare(); if (circle) pic = pt.drawCircle();

From the above example, you may see that the Shape pic's type depends on the condition given. The variable pic may be a line or square or a circle.

You may use several constructors with different parameters to instantiate the object you want. It is another way to design with Factory pattern. For example, class Painting { ... Painting(Point a, Point b) { new Line(a, b); //draw a line } Painting(Point a, int w, int h) { new Square(a, w, h); //draw a square } Painting(Point a, int r){ new Circle(a, r); //draw a circle } ...

}

You may use several methods to finish the drawing jobs. It is so-called factory method pattern. for example, class Painting { ... Painting(Point a, Point b) { draw(a, b); //draw a line } Painting(Point a, int w, int h) { draw(a, w, h); //draw a square } Painting(Point a, int r){ draw(a, r); //draw a circle } ... }

The above draw() methods are overloaded.

Here is a popular example of Factory design pattern. For example, you have several database storages located in several places. The program working on the database is the same. The user may choose local mode or remote mode. The condition is the choice by the user. You may design your program with Factory pattern. When the local mode is set, you may instantiate an object to work on the local database. If the remote mode is set, you may instantiate an object which may have more job to do like remote connection, downloading, etc. interface DatabaseService { public DataInfo getDataInfo() throws Exception; public FieldInfo getFieldInfo() throws Exception; public void write(FieldInfo fi) throws Exception; public void modify(FieldInfo fi) throws Exception; public void delete(FieldInfo fi) throws Exception; //... } class Data implements DatabaseService { public public public public public public public //....

Data(String fileName) {...}; Data(URL url, String fileName) {....}; DataInfo getDataInfo() throws Exception {...}; FieldInfo getFieldInfo() throws Exception {...}; void write(FieldInfo fi) throws Exception {...}; void modify(FieldInfo fi) throws Exception {...}; void delete(FieldInfo fi) throws Exception {...};

} class DataManager{ Data data = null; ... if (local) {

data = new Data(localFile); ... } if (remote){ data = new Data(connectRemote, databaseFile); ... } data.write(someInfo); data.modify(someInfo); .... }

To illustrate how to use factory design pattern with class level implementation, here is a real world example. A company has a website to display testing result from a plain text file. Recently, the company purchased a new machine which produces a binary data file, another new machine on the way, it is possible that one will produce different data file. How to write a system to deal with such change. The website just needs data to display. Your job is to provide the specified data format for the website. Here comes a solution. Use an interface type to converge the different data file format. The following is a skeleton of implementation. //Let's say the interface is Display interface Display { //load a file public void load(String fileName); //parse the file and make a consistent data type public void formatConsistency(); } //deal with plain text file class CSVFile implements Display{ public void load(String textfile) { System.out.println("load from a txt file"); } public void formatConsistency() { System.out.println("txt file format changed"); } } //deal with XML format file class XMLFile implements Display {

}

public void load(String xmlfile) { System.out.println("load from an xml file"); } public void formatConsistency() { System.out.println("xml file format changed"); }

//deal with binary format file class DBFile implements Display { public void load(String dbfile) { System.out.println("load from a db file"); } public void formatConsistency() { System.out.println("db file format changed"); } } //Test the functionality class TestFactory { public static void main(String[] args) { Display display = null; //use a command line data as a trigger if (args[0].equals("1")) display = new CSVFile(); else if (args[0].equals("2")) display = new XMLFile(); else if (args[0].equals("3")) display = new DBFile(); else System.exit(1); //converging code follows display.load(""); display.formatConsistency();

} } //after compilation and run it C:\>java TestFactory 1 load from a txt file txt file format changed C:\>java TestFactory 2 load from an xml file xml file format changed C:\>java TestFactory 3 load from a db file db file format changed

In the future, the company may add more data file with different format, a programmer just adds a new class in accordingly. Such design saves a lot of code and is easy to maintain.

Prototype

Definition Cloning an object by reducing the cost of creation.

Where to use & benefits • • • • • • • •

When there are many subclasses that differ only in the kind of objects, A system needs independent of how its objects are created, composed, and represented. Dynamic binding or loading a method. Use one instance to finish job just by changing its state or parameters. Add and remove objects at runtime. Specify new objects by changing its structure. Configure an application with classes dynamically. Related patterns include o Abstract Factory, which is often used together with prototype. An abstract factory may store some prototypes for cloning and returning objects. o Composite, which is often used with prototypes to make a part-whole relationship. o Decorator, which is used to add additional functionality to the prototype.

Example Dynamic loading is a typical object-oriented feature and prototype example. For example, overriding method is a kind of prototype pattern. interface Shape { public void draw(); } class Line implements Shape { public void draw() { System.out.println("line"); } } class Square implements Shape { public void draw() { System.out.println("square"); } } class Circle implements Shape { public void draw() { System.out.println("circle"); } } class Painting { public static void main(String[] args) { Shape s1 = new Line(); Shape s2 = new Square(); Shape s3 = new Circle();

paint(s1); paint(s2); paint(s3);

} static void paint(Shape s) { if ( s instanceof Line) s.draw(); if (s instanceof Square) s.draw(); if (s instanceof Circle) s.draw(); } }

C:\ Command Prompt C:\> java Painting line square circle The paint method takes a variable of Shape type at runtime. The draw method is called based on the runtime type. Overloading method is a kind of prototype too. class Painting { public void draw(Point p, Point p2) { //draw a line } public void draw(Point p, int x, int y) { //draw a square } public void draw(Point p, int x) { //draw a circle } }

The draw method is called to draw the related shape based on the parameters it takes. The prototype is typically used to clone an object, i.e. to make a copy of an object. When an object is complicated or time consuming to be created , you may take prototype pattern to make such object cloneable. Assume the Complex class is a complicated, you need to implement Cloneable interface and override the clone method(protected Object clone()). class Complex implements Cloneable { int[] nums = {1,2,3,4,5}; public Object clone() { try { return super.clone(); }catch(CloneNotSupportedException cnse) { System.out.println(cnse.getMessage()); return null;

} } int[] getNums() { return nums; }

} class Test { static Complex c1 = new Complex(); static Complex makeCopy() { return (Complex)c1.clone(); } public static void main(String[] args) { Complex c1 = makeCopy(); int[] mycopy = c1.getNums(); for(int i = 0; i < mycopy.length; i++) System.out.print(mycopy[i]); } }

C:\ Command Prompt C:\> java Test 12345 Cloning is a shallow copy of the original object. If the cloned object has been changed, the original object will be changed accordingly. See the following alteration. class Complex implements Cloneable { int[] nums = {1,2,3,4,5}; public Object clone() { try { return super.clone(); }catch(CloneNotSupportedException cnse) { System.out.println(cnse.getMessage()); return null; } } int[] getNums() { return nums; } } class Test { Complex c1 = new Complex(); Complex makeCopy() { return (Complex)c1.clone(); } public static void main(String[] args) { Test tp = new Test(); Complex c2 = tp.makeCopy(); int[] mycopy = c2.getNums(); mycopy[0] = 5; System.out.println(); System.out.print("local array: "); for(int i = 0; i < mycopy.length; i++) System.out.print(mycopy[i]); System.out.println();

System.out.print("cloned object: "); for(int ii = 0; ii < c2.nums.length; ii++) System.out.print(c2.nums[ii]); System.out.println();

}

System.out.print("original object: "); for(int iii = 0; iii < tp.c1.nums.length; iii++) System.out.print(tp.c1.nums[iii]);

C:\ Command Prompt C:\> java Test local array: 52345 cloned object: 52345 original object: 52345

To avoid such side effect, you may use a deep copy instead of a shallow copy. The following shows the alteration to the above example, note that the Complex class doesn't implement Cloneable interface. class Complex { int[] nums = {1,2,3,4,5}; public Complex clone() { return new Complex(); } int[] getNums() { return nums; } } class Test2 { Complex c1 = new Complex(); Complex makeCopy() { return (Complex)c1.clone(); } public static void main(String[] args) { Test2 tp = new Test2(); Complex c2 = tp.makeCopy(); int[] mycopy = c2.getNums(); mycopy[0] = 5; System.out.println(); System.out.print("local array: "); for(int i = 0; i < mycopy.length; i++) System.out.print(mycopy[i]); System.out.println(); System.out.print("cloned object: "); for(int ii = 0; ii < c2.nums.length; ii++) System.out.print(c2.nums[ii]); System.out.println(); System.out.print("original object: "); for(int iii = 0; iii < tp.c1.nums.length; iii++) System.out.print(tp.c1.nums[iii]);

}

}

C:\ Command Prompt C:\> java Test2 local array: 52345 cloned object: 52345 original object: 12345

Builder Definition Construct a complex object from simple objects step by step.

Where to use & benefits • • • • •

Make a complex object by specifying only its type and content. The built object is shielded from the details of its construction. Want to decouple the process of building a complex object from the parts that make up the object. Isolate code for construction and representation. Give you finer control over the construction process. Related patterns include o Abstract Factory, which focuses on the layer over the factory pattern (may be simple or complex), whereas a builder pattern focuses on building a complex object from other simple objects. o Composite, which is often used to build a complex object.

Example To build a house, we will take several steps: 1. 2. 3. 4.

build foundation, build frame, build exterior, build interior.

Let's use an abstract class HouseBuilder to define these 4 steps. Any subclass of HouseBuilder will follow these 4 steps to build house (that is to say to implement these 4 methods in the subclass). Then we use a WorkShop class to force the order of these 4 steps (that is to say that we have to build interior after having finished first three steps).

The TestBuilder class is used to test the coordination of these classes and to check the building process. import java.util.*; class WorkShop { //force the order of building process public void construct(HouseBuilder hb) { hb.buildFoundation(); hb.buildFrame(); hb.buildExterior(); hb.buildInterior(); } } //set steps for building a house abstract class HouseBuilder { protected House house = new House(); protected String showProgress() { return house.toString(); } abstract abstract abstract abstract

public public public public

void void void void

buildFoundation(); buildFrame(); buildExterior(); buildInterior();

} class OneStoryHouse extends HouseBuilder { public OneStoryHouse(String features) { house.setType(this.getClass() + " " + features); } public void buildFoundation() { //doEngineering() //doExcavating() //doPlumbingHeatingElectricity() //doSewerWaterHookUp() //doFoundationInspection() house.setProgress("foundation is done"); } public void buildFrame() { //doHeatingPlumbingRoof() //doElectricityRoute() //doDoorsWindows() //doFrameInspection() house.setProgress("frame is done"); } public void buildExterior() { //doOverheadDoors() //doBrickWorks() //doSidingsoffitsGutters() //doDrivewayGarageFloor()

}

}

//doDeckRail() //doLandScaping() house.setProgress("Exterior is done");

public void buildInterior() { //doAlarmPrewiring() //doBuiltinVacuum() //doInsulation() //doDryWall() //doPainting() //doLinoleum() //doCabinet() //doTileWork() //doLightFixtureBlinds() //doCleaning() //doInteriorInspection() house.setProgress("Interior is under going"); }

class TwoStoryHouse extends HouseBuilder { public TwoStoryHouse(String features) { house.setType(this.getClass() + " " + features); } public void buildFoundation() { //doEngineering() //doExcavating() //doPlumbingHeatingElectricity() //doSewerWaterHookUp() //doFoundationInspection() house.setProgress("foundation is done"); } public void buildFrame() { //doHeatingPlumbingRoof() //doElectricityRoute() //doDoorsWindows() //doFrameInspection() house.setProgress("frame is under construction"); } public void buildExterior() { //doOverheadDoors() //doBrickWorks() //doSidingsoffitsGutters() //doDrivewayGarageFloor() //doDeckRail() //doLandScaping() house.setProgress("Exterior is waiting to start"); } public void buildInterior() { //doAlarmPrewiring() //doBuiltinVacuum() //doInsulation()

}

//doDryWall() //doPainting() //doLinoleum() //doCabinet() //doTileWork() //doLightFixtureBlinds() //doCleaning() //doInteriorInspection() house.setProgress("Interior is not started yet");

} class House { private String type = null; private List features = new ArrayList(); public House() { } public House(String type) { this.type = type; } public void setType(String type) { this.type = type; } public String getType() { return type; } public void setProgress(String s) { features.add(s); }

}

public String toString() { StringBuffer ff = new StringBuffer(); String t = type.substring(6); ff.append(t + "\n "); for (int i = 0; i < features.size(); i ++) { ff.append(features.get(i) + "\n "); } return ff.toString(); }

class TestBuilder

{

public static void main(String[] args) { HouseBuilder one = new OneStoryHouse("2 bedrooms, 2.5 baths, 2car garage, 1500 sqft"); HouseBuilder two = new TwoStoryHouse("4 bedrooms, 4 baths, 3-car garage, 5000 sqft"); WorkShop shop = new WorkShop();

shop.construct(one); shop.construct(two); System.out.println("Check house building progress: \n"); System.out.println(one.showProgress()); System.out.println(two.showProgress());

} } //need jdk1.5 above to compile

C:\ Command Prompt C:\> javac TestBuilder.java C:\> java TestBuilder Check house building progress: OneStoryHouse 2 bedrooms, 2.5 baths, 2-car garage, 1500 sqft foundation is done frame is done Exterior is done Interior is under going TwoStoryHouse 4 bedrooms, 4 baths, 3-car garage, 5000 sqft foundation is done frame is under construction Exterior is waiting to start Interior is not started yet C:\>

To fine tune the above example, every do method can be designed as a class. Similar functional class can be designed once and used by other classes. e.g. Window, Door, Kitchen, etc. Another example, such as writing a Pizza program. Every gradient can be designed as a class. One pizza at least consists of several gradients. Different pizza has different gradients. A builder pattern may be adopted.

Singleton Definition One instance of a class or one value accessible globally in an application.

Where to use & benefits

• • • • • • •

Ensure unique instance by defining class final to prevent cloning. May be extensible by the subclass by defining subclass final. Make a method or a variable public or/and static. Access to the instance by the way you provided. Well control the instantiation of a class. Define one value shared by all instances by making it static. Related patterns include o Abstract factory, which is often used to return unique objects. o Builder, which is used to construct a complex object, whereas a singleton is used to create a globally accessible object. o Prototype, which is used to copy an object, or create an object from its prototype, whereas a singleton is used to ensure that only one prototype is guaranteed.

Example One file system, one window manager, one printer spooler, one Test engine, one Input/Output socket and etc. To design a Singleton class, you may need to make the class final like java.Math, which is not allowed to subclass, or make a variable or method public and/or static, or make all constructors private to prevent the compiler from creating a default one. For example, to make a unique remote connection, final class RemoteConnection { private Connect con; private static RemoteConnection rc = new RemoteConnection(connection); private RemoteConnection(Connect c) { con = c; .... } public static RemoteConnection getRemoteConnection() { return rc; } public void setConnection(Connect c) { this(c); } } usage: RemoteConnection rconn = RemoteConnection.getRemoteConnection; rconn.loadData(); ... The following statement may fail because of the private constructor RemoteConnection con = new RemoteConnection(connection); //failed

//failed because you cannot subclass it (final class) class Connection extends RemoteConnection {}

For example, to use a static variable to control the instance; class Connection { public static boolean haveOne = false; public Connection() throws Exception{ if (!haveOne) { doSomething(); haveOne = true; }else { throw new Exception("You cannot have a second instance"); } } public static Connection getConnection() throws Exception{ return new Connection(); } void doSomething() {} //... public static void main(String [] args) { try { Connection con = new Connection(); //ok }catch(Exception e) { System.out.println("first: " +e.getMessage()); } try { Connection con2 = Connection.getConnection(); //failed. }catch(Exception e) { System.out.println("second: " +e.getMessage()); } } }

C:\ Command Prompt C:\> java Connection second: You cannot have a second instance For example to use a public static variable to ensure a unique. class Employee { public static final int companyID = 12345; public String address; //... } class HourlyEmployee extends Employee { public double hourlyRate; //.... } class SalaryEmployee extends Employee { public double salary; //... } class Test {

}

public static void main(String[] args) { Employee Evens = new Employee(); HourlyEmployee Hellen = new HourlyEmployee(); SalaryEmployee Sara = new SalaryEmployee(); System.out.println(Evens.companyID == Hellen.companyID); //true System.out.println(Evens.companyID == Sara.companyID); //true }

C:\ Command Prompt C:\> java Test true true The companyID is a unique and cannot be altered by all subclasses. Note that Singletons are only guaranteed to be unique within a given class loader. If you use the same class across multiple distinct enterprise containers, you'll get one instance for each container.

Structural Patterns::::: Adapter Definition Convert the existing interfaces to a new interface to achieve compatibility and reusability of the unrelated classes in one application. Also known as Wrapper pattern.

Where to use & benefits • • • • • • • • •

Try to match an interface(WindowAdapter, etc.) Make unrelated classes work together. Multiple compatibility. Increase transparency of classes. Make a pluggable kit. Delegate objects. Highly class reusable. Achieve the goal by inheritance or by composition Related patterns include o Proxy, which provides the same interface as its subject, whereas an adapter provides a different interface to the object it adapts. o Decorator, which focuses on adding new functions to an object, whereas an adapter coordinates two different objects.

o

Bridge, which tries to separate an interface from its implementation and make an object vary independently, whereas an adapter tries to change and cooperate the interface of an object.

Example The famous adapter classes in Java API are WindowAdapter,ComponentAdapter, ContainerAdapter, FocusAdapter, KeyAdapter, MouseAdapter and MouseMotionAdapter. As you know, WindowListner interface has seven methods. Whenever your class implements such interface, you have to implements all of the seven methods. WindowAdapter class implements WindowListener interface and make seven empty implementation. When you class subclass WindowAdapter class, you may choose the method you want without restrictions. The following give such an example. public interface Windowlistener { public void windowClosed(WindowEvent e); public void windowOpened(WindowEvent e); public void windowIconified(WindowEvent e); public void windowDeiconified(WindowEvent e); public void windowActivated(WindowEvent e); public void windowDeactivated(WindowEvent e); public void windowClosing(WindowEvent e); } public class WindowAdapter implements WindowListner{ public void windowClosed(WindowEvent e){} public void windowOpened(WindowEvent e){} public void windowIconified(WindowEvent e){} public void windowDeiconified(WindowEvent e){} public void windowActivated(WindowEvent e){} public void windowDeactivated(WindowEvent e){} public void windowClosing(WindowEvent e){} }

Here is a test program import javax.swing.*; import java.awt.event.*; class Test extends JFrame { public Test () { setSize(200,200); setVisible(true); addWindowListener(new Closer()); } public static void main(String[] args) { new Test(); } class Closer extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0);

}

}

}

To reuse classes and make new class compatible with existing ones. For example, A clean system is already designed, you want to add more job in, the Extra interface uses adapter pattern to plug in the existing system. interface Clean { public void makeClean(); } class Office implements Clean{ public void makeClean() { System.out.println("Clean Office"); } } class Workshop implements Clean{ public void makeClean() { System.out.println("Clean Workshop"); } } interface Extra extends Clean{ public void takeCare(); } class Facility implements Extra{ public void makeClean() { System.out.println("Clean Facility"); } public void takeCare() { System.out.println("Care has been taken"); } } In order to reuse Workshop and Office classes, we create an adapter interface Extra and add new job takeCare in the system. class Test { static void Jobs (Extra job) { if (job instanceof Clean) ((Clean)job).makeClean(); if (job instanceof Extra) ((Extra)job).takeCare(); } public static void main(String[] args) { Extra e = new Facility(); Jobs(e); Clean c1 = new Office(); Clean c2 = new Workshop(); c1.makeClean(); c2.makeClean(); e.makeClean(); } }

C:\ Command Prompt C:\> java Test Clean Facility Care has been taken Clean Office Clean Workshop Clean Facility By composition, we can achieve adapter pattern. It is also called wrapper. For example, a Data class has already been designed and well tested. You want to adapt such class to your system. You may declare it as a variable and wrapper or embed it into your class. //well-tested class class Data { public void add(Info){} public void delete(Info) {} public void modify(Info){} //... } //Use Data class in your own class class AdaptData { Data data; public void add(Info i) { data.add(i); //more job } public void delete(Info i) { data.delete(i); //more job } public void modify(Info i) { data.modify(i); //more job } //more stuff here //... }

Bridge Definition Decouple an abstraction or interface from its implementation so that the two can vary independently.

Where to use & benefits

• • • • •

Want to separate abstraction and implementation permanently Share an implementation among multiple objects Want to improve extensibility Hide implementation details from clients Related patterns include o Abstract Factory, which can be used to create and configure a particular bridge. o Adapter, which makes unrelated classes work together, whereas a bridge makes a clear-cut between abstraction and implementation.

Examples If you have a question database, you may want to develop a program to display it based on the user selection. The following is a simple example to show how to use a Bridge pattern to decouple the relationship among the objects. import java.util.*; //abstraction interface Question { public public public public public public

void void void void void void

nextQuestion(); priorQuestion(); newQuestion(String q); deleteQuestion(String q); displayQuestion(); displayAllQuestions();

} //implementation class QuestionManager { protected Question questDB; //instantiate it later public String catalog; public QuestionManager(String catalog) { this.catalog = catalog; } public void next() { questDB.nextQuestion(); } public void prior() { questDB.priorQuestion(); } public void newOne(String quest) { questDB.newQuestion(quest); } public void delete(String quest) {

questDB.deleteQuestion(quest);

}

public void display() { questDB.displayQuestion(); }

}

public void displayAll() { System.out.println("Question Catalog: " + catalog); questDB.displayAllQuestions(); }

//further implementation class QuestionFormat extends QuestionManager { public QuestionFormat(String catalog){ super(catalog); } public void displayAll() { System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~"); super.displayAll(); System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~"); }

}

//decoupled implementation class JavaQuestions implements Question { private List questions = new ArrayList(); private int current = 0; public JavaQuestions() { //load from a database questions.add("What is questions.add("What is questions.add("What is questions.add("What is questions.add("What is questions.add("What is questions.add("What is

and fill in the container Java? "); an interface? "); cross-platform? "); UFT-8? "); abstract? "); Thread? "); multi-threading? ");

} public void nextQuestion() { if( current <= questions.size() - 1 ) current++; } public void priorQuestion() { if( current > 0 ) current--; }

public void newQuestion(String quest) { questions.add(quest); } public void deleteQuestion(String quest) { questions.remove(quest); } public void displayQuestion() { System.out.println( questions.get(current) ); } public void displayAllQuestions() { for (String quest : questions) { System.out.println(quest); } }

}

class TestBridge { public static void main(String[] args) { QuestionFormat questions = new QuestionFormat("Java Language"); questions.questDB = new JavaQuestions();//can be hooked up with other question class //questions.questDB = new CsharpQuestions(); //questions.questDB = new CplusplusQuestions(); questions.display(); questions.next(); questions.newOne("What is object? "); questions.newOne("What is reference type?"); }

questions.displayAll();

} //need jdk1.5 to compile

C:\ Command Prompt C:\> javac TestBridge.java C:\> java TestBridge What is Java? ~~~~~~~~~~~~~~~~~~~~~~~~ Question Catalog: Java Language What is Java? What is an interface? What is cross-platform? What is UFT-8? What is abstract? What is Thread? What is multi-threading? What is object? What is reference type? ~~~~~~~~~~~~~~~~~~~~~~~~ C:\>

Note that the JavaQuestion class can be launched independently and work as its own system. Here we just show you how to use Bridge pattern to decouple the interface from its implementation.

Composite Definition Build a complex object out of elemental objects and itself like a tree structure.

Where to use & benefits • • •

Want to represent a part-whole relationship like tree folder system Group components to form larger components, which in turn can be grouped to form still larger components. Related patterns include o Decorator, which is often used with composite pattern and with the same parent class. o Flyweight, which is used with composite pattern to share components. o Iterator, which is used to traverse the composites. o Visitor, which localizes operations across composite and leaf classes.

Example

A component has many elements and itself which has many elements and itself, etc. A file system is a typical example. Directory is a composite pattern. When you deal with Directory object, if isFile() returns true, work on file, if isDirectory() returns true, work on Directory object. class Directory { Directory dir; File[] f; ... boolean isDirectory() { return f == null; } boolean isFile() { return f != null; } File getFile(int i) { if (isFile()) return f[i]; return null' } Directory getDirectory() { if (isDirectory()) return dir; return null; } .... }

For example, General Manager may have several employees and some of employees are Managers which have several employees. To illustrate such issue, we design a simple Manager class. class Employee { String name; double salary; Employee(String n, double s){ name = n; salary = s; } String getName() { return name; } double getSalary() { return salary; } public String toString() { return "Employee " + name; } } class Manager { Manager mgr; Employee[] ely; String dept;

Manager(Manager mgr,Employee[] e, String d ) { this(e, d); this.mgr = mgr; }

}

Manager(Employee[] e, String d) { ely = e; dept =d; } String getDept() { return dept; } Manager getManager() { return mgr; } Employee[] getEmployee() { return ely; } public String toString() { return dept + " manager"; }

class Test { public static void main(String[] args) { Employee[] e1 = {new Employee("Aaron", 50), new Employee("Betty", 60)}; Manager m1 = new Manager(e1, "Accounting"); Employee[] e2 = {new Employee("Cathy", 70), new Employee("Dan", 80), new Employee("Eliz", 90)}; Manager m2 = new Manager(m1, e2, "Production"); System.out.println(m2); Employee[] emp = m2.getEmployee(); if (emp != null) for (int k = 0; k < emp.length; k++) System.out.println(" "+emp[k]+" Salary: $"+ emp[k].getSalary()); Manager m = m2.getManager(); System.out.println(" " + m); if (m!= null) { Employee[] emps = m.getEmployee(); if (emps != null) for (int k = 0; k < emps.length; k++) System.out.println(" " + emps[k]+" Salary: $"+ emps[k].getSalary()); } }

}

C:\ Command Prompt C:\> java Test Production manager Employee Cathy Salary: $70.0 Employee Dan Salary: $80.0 Employee Eliz Salary: $90.0 Accounting manager Employee Aaron Salary: $50.0 Employee Betty Salary: $60.0

Decorator Definition Attach additional responsibilities or functions to an object dynamically or statically. Also known as Wrapper.

Where to use & benefits • • • • • •

Provide an alternative to subclassing. Add new function to an object without affecting other objects. Make a responsibility easily added and removed dynamically. More flexibility than static inheritance. Transparent to the object. Related patterns include o Adapter pattern, which provides a different interface to the object it adapts, whereas a decorator changes an object's responsibilities, o Proxy pattern, which controls access to the object, whereas a decorator focuses on adding new functions to an object, o Composite pattern, which aggregates an object, whereas a decorator adds additional responsibilities to an object, and o Strategy pattern, which changes the guts of an object, whereas a decorator changes the skin of an object. o Facade pattern, which provides a way of hiding a complex class, whereas a decorator adds function by wrapping a class.

Example A JScrollPane object can be used to decorate a JTextArea object or a JEditorPane object. A window can be decorated with different borders like BevelBorder, CompoundBorder, EtchedBorder TitledBorder etc. These border classes working as decorators are provided in Java API.

Decorator pattern can be used in a non-visual fashion. For example, BufferedInputStream, DataInputStream, and CheckedInputStream are decorating objects of FilterInputStream class. These decorators are standard Java API classes. To illustrate a simple decorator pattern in non-visual manner, we design a class that prints a number. We create a decorator class that adds a text to the Number object to indicate that such number is a random number. Of course we can subclass the Number class to achieve the same goal. But the decorator pattern provides us an alternative way. import java.util.Random; class Number { public void print() { System.out.println(new Random().nextInt()); } } class Decorator { public Decorator() { System.out.print("Random number: ");//add a description to the number printed new Number().print(); } } class SubNumber extends Number{ public SubNumber() { super(); System.out.print("Random number: "); print(); } } class Test { public static void main(String[] args) { new Decorator(); new SubNumber(); } } java Test Random number: 145265744 Random number: 145265755

Façade Definition Make a complex system simpler by providing a unified or general interface, which is a higher layer to these subsystems.

Where to use & benefits • • • • • • • •

Want to reduce complexities of a system. Decouple subsystems , reduce its dependency, and improve portability. Make an entry point to your subsystems. Minimize the communication and dependency between subsystems. Security and performance consideration. Shield clients from subsystem components. Simplify generosity to specification. Related patterns include o Abstract Factory, which is often used to create an interface for a subsystem in an independent way, and can be used as an alternative way to a facade. o Singleton, which is often used with a facade. o Mediator, which is similar to facade, but a facade doesn't define new functionality to the subsystem.

Example JDBC design is a good example of Façade pattern. A database design is complicated. JDBC is used to connect the database and manipulate data without exposing details to the clients. Security of a system may be designed with Façade pattern. Clients' authorization to access information may be classified. General users may be allowed to access general information; special guests may be allowed to access more information; administrators and executives may be allowed to access the most important information. These subsystems may be generalized by one interface. The identified users may be directed to the related subsystems. interface General { public void accessGeneral(); } interface Special extends General { public void accessSpecial(); } interface Private extends General { public void accessPrivate(); } class GeneralInfo implements General { public void accessGeneral() { //... } //... } class SpecialInfo implements Special{ public void accessSpecial() {

//... } public void accessGeneral() {} //... } class PrivateInfo implements Private, Special { public void accessPrivate() { // ... } public void accessSpecial() { //... } public void accessGeneral() { // ... } //... } class Connection { //... if (user if (user if (user if (user //...

is is is is

unauthorized) throw new Exception(); general) return new GeneralInfo(); special) return new SpecialInfo(); executive) return new PrivateInfo();

}

The above code example illustrates that the whole system is not exposed to the clients. It depends on the user classification. Mr. SudHakar Chavali proposes a better design, similar to the above, but avoids repeated code. Look at code below. interface General { public void accessGeneral(); }

interface Special extends General { public void accessSpecial(); } interface Private extends General { public void accessPrivate(); } class GeneralInfo implements General { public void accessGeneral() { //... }

//... } class SpecialInfo extends GeneralInfo implements Special{ public void accessSpecial() { }

//...

} class PrivateInfo extends SpecialInfo implements Private { public void accessPrivate() { // ... } //... }

To avoid repeated code, SpecialInfo become subclass of GeneralInfo and PrivateInfo becomes subclass of SpecialInfo. When a person is exposed to special information, that person is allowed to access general information also. When a person is exposed to private information, that person is allowed to access general information and special information also.

When you design a mortgage process system, you may consider the process of checking client's bank, credit and other loan information. Facade design may be a choice.

Flyweight Definition Make instances of classes on the fly to improve performance efficiently, like individual characters or icons on the screen.

Where to use & benefits • • •

Need to instantiate a large amount of small and fine-grained classes. Need icons to represent object. An object extrinsic state can be shared by classes.

Reduce the number of objects created, decrease memory footprint and increase performance. Increase runtime cost associated with transferring, finding, or computing extrinsic data. Related patterns include o Composite, which supports recursive structures, whereas an flyweight is often applied on it. o Factory Method, which produces specific object upon requirement, whereas an flyweight uses it to reduce objects. o State, which allows an object to alter its behavior when its internal state is changed, whereas a flyweight is best implemented on it. o Strategy, which allows an algorithm vary independently to suit its needs, whereas a flyweight is based on such strategy.

• • •

Examples In order to share an object, we may declare an interface and an intrinsic state through which flyweights can receive and act on it. If you want to show a file system with folders to show the directories or subdirectories, you don't need to load all the files or directories at one loading time. You may show the upper level folders first. If the user clicks a folder, then load its subdirectories and files. The shared trigger is mouse-clicked. The composite pattern may be combined to define the flyweight system. class Folder { void draw(..) {} } class FolderFactory { ... if (selected) { return aFolder; else return aFile; ... } ...

To show how to use flyweight to reduce object creation, we will make a program to draw 1000 circles with 6 different colors. Before we customize it to a flyweight design, it is coded as follows: import import import import import

java.awt.*; java.awt.Color; java.awt.event.*; javax.swing.*; javax.swing.event.*;

class Test extends JFrame{ private static final Color colors[] = { Color.red, Color.blue, Color.yellow, Color.orange,

Color.black, private static final int WIDTH_ = 400, HEIGHT = 400, NUMBER_OF_CIRCLES = 1000;

Color.white };

public Test() { Container contentPane = getContentPane(); JButton button = new JButton("Draw Circle"); final JPanel panel = new JPanel(); contentPane.add(panel, BorderLayout.CENTER); contentPane.add(button, BorderLayout.SOUTH); setSize(WIDTH,HEIGHT); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { Graphics g = panel.getGraphics(); for(int i=0; i < NUMBER_OF_CIRCLES; ++i) { g.setColor(getRandomColor()); int r = getRandomR(); g.drawOval(getRandomX(), getRandomY(), r, r); } }

}); }

}

private int getRandomX() { return (int)(Math.random()*WIDTH ); } private int getRandomY() { return (int)(Math.random()*HEIGHT); } private int getRandomR() { return (int)(Math.random()*(HEIGHT/10)); } private Color getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } public static void main(String[] args) { Test test = new Test(); }

Copy, paste above code, and run it to see the functionality.

C:\ Command Prompt C:\> java Test

Note that the above program doesn't take advantage of reusability of OOP. We will customize it and make a Circle object, so the Circle object can be reused. class Circle { private Color color; public Circle(Color color) { this.color = color; } public void draw(Graphics g, int x, int y, int r) { g.setColor(color); g.drawOval(x, y, r, r); } }

Then we rewrite the program. It is possible for people to rewrite with Circle object in the following way: import import import import import

java.awt.*; java.awt.Color; java.awt.event.*; javax.swing.*; javax.swing.event.*;

class Test extends JFrame{ private static final Color colors[] = { Color.red, Color.blue, Color.yellow, Color.orange,

Color.black, private static final int WIDTH = 400, HEIGHT = 400, NUMBER_OF_CIRCLES = 1000;

Color.white };

public Test() { Container contentPane = getContentPane(); JButton button = new JButton("Draw Circle"); final JPanel panel = new JPanel(); contentPane.add(panel, BorderLayout.CENTER); contentPane.add(button, BorderLayout.SOUTH); setSize(WIDTH ,HEIGHT); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { Graphics g = panel.getGraphics(); for(int i=0; i < NUMBER_OF_CIRCLES; ++i) { Circle circle = new Circle(getRandomColor()); circle.draw(g, getRandomX(), getRandomY(), getRandomR());//1000 object created. } } }); }

}

private int getRandomX() { return (int)(Math.random()*WIDTH ); } private int getRandomY() { return (int)(Math.random()*HEIGHT); } private int getRandomR() { return (int)(Math.random()*(HEIGHT/10)); } private Color getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } public static void main(String[] args) { Test test = new Test(); }

From the above code, you may note that 1000 circle object has been created. It is memory consuming. To improve it, we will create a CircleFactory class to customize it by using flyweight design pattern. Since we just draw circle with different colors, we can store color info in a hashmap. If a circle has been drawn, the new circle will be checked with color. If the circle with the same color has been found in the hashmap, the circle will share the instance which is picked up from the hashmap instead of creating a new one. We will

reuse the object with different state, that is to say we will share the instance and draw the circle with different start position and radius on the fly. class CircleFactory { //store color private static final HashMap circleByColor = new HashMap(); public static Circle getCircle(Color color) { Circle circle = (Circle)circleByColor.get(color); if(circle == null) { circle = new Circle(color); circleByColor.put(color, circle); System.out.println("Creating " + color + " circle");//see how many objects we create on command line } return circle; } }

So our test program will be coded as follows: import import import import import import

java.awt.*; java.util.HashMap; java.awt.Color; java.awt.event.*; javax.swing.*; javax.swing.event.*;

class Test extends JFrame{ private static final Color colors[] = { Color.red, Color.blue, Color.yellow, Color.orange, Color.black, Color.white }; private static final int WIDTH = 400, HEIGHT = 400, NUMBER_OF_CIRCLES = 1000; public Test() { Container contentPane = getContentPane(); JButton button = new JButton("Draw Circle"); final JPanel panel = new JPanel(); contentPane.add(panel, BorderLayout.CENTER); contentPane.add(button, BorderLayout.SOUTH); setSize(WIDTH,HEIGHT); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { Graphics g = panel.getGraphics(); for(int i=0; i < NUMBER_OF_CIRCLES; ++i) { Circle circle = CircleFactory.getCircle(getRandomColor());

circle.draw(g, getRandomX(), getRandomY(),getRandomR()); //Since we have 6 different colors, we have 6 objects created.

} }

}); } public static void main(String[] args) { Test test = new Test(); } private int getRandomX() { return (int)(Math.random()*WIDTH ); } private int getRandomY() { return (int)(Math.random()*HEIGHT); } private int getRandomR() { return (int)(Math.random()*(HEIGHT/10)); } private Color getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } } class CircleFactory { private static final HashMap circleByColor = new HashMap(); public static Circle getCircle(Color color) { Circle circle = (Circle)circleByColor.get(color); if(circle == null) { circle = new Circle(color); circleByColor.put(color, circle); System.out.println("Creating " + color + " circle"); } return circle; }

}

class Circle { private Color color;

}

public Circle(Color color) { this.color = color; } public void draw(Graphics g, int x, int y, int r) { g.setColor(color); g.drawOval(x, y, r, r); }

Copy, paste above code and run it. You will see the printout from the command line, that you only have 6 objects created, not 1000 objects because you only have 6 colors. Such a big reduction of object creation will improve your program performance dramatically.

C:\ Command Prompt C:\> java Test Creating java.awt.Color[r=255,g=0,b=0] circle Creating java.awt.Color[r=0,g=0,b=0] circle Creating java.awt.Color[r=255,g=200,b=0] circle Creating java.awt.Color[r=255,g=255,b=0] circle Creating java.awt.Color[r=0,g=0,b=255] circle Creating java.awt.Color[r=255,g=255,b=255] circle

Flyweight design is effective with instantiating a large amount of small and fine-grained classes by combining with factory design pattern. If you have jdk1.5 installed, you may need to use a tool to check if you save the memory by running your commands as follows:

C:\ Command Prompt C:\> java -Dcom.sun.management.jmxremote Test And open another console as follows:

C:\ Command Prompt C:\> jconsole

The jconsole tool will hook up your program Test to give your statistic numbers about your program, such as threads, heap, memory, VM, etc. String class is designed with Flyweight design pattern. It has similar structure as above example. When you create a string constant, such constant is stored in a pool. When the second string is created, it will be checked to see if it has been created. If it is true, the second string instance will be picked up from the string pool instead of creating a new one. This is why the following code makes sense, but bothers many people. String s1 = "hello"; String s2 = "hello"; //store in a string pool. String s3 = new String("hello"); System.out.println(s1==s2); //true, share the same memmory address System.out.println(s1==s3); //false

Proxy Definition Use a simple object to represent a complex one or provide a placeholder for another object to control access to it.

Where to use & benefits • • • • • •

If creating an object is too expensive in time or memory. Postpone the creation until you need the actual object. Load a large image (time consuming). Load a remote object over network during peak periods. Access right is required to a complex system. Related patterns include o Adapter pattern, which provides a different interface to the object it adapts, whereas a proxy provides the same interface as its subject, and o Decorator pattern, which focuses on adding new functions to an object, whereas a proxy controls access to the object.

Example When loading a large image, you may create some light object to represent it until the image is loaded completely. Usually a proxy object has the same methods as the object it represents. Once the object is loaded, it passes on the actual object. For example, abstract class Graphic { public abstract void load();

public abstract void draw(); ... } class Image extends Graphic{ public void load() { ... } public void draw() { ... } ... } class ImgProxy extends Graphic { public void load() { if(image == null) { image = new Image(filename); } ... public void draw() { ... } ...

}

Behavioral Patterns::::::

Chain of Responsibility Definition Let more than one object handle a request without their knowing each other. Pass the request to chained objects until it has been handled.

Where to use & benefits • • • • •

One request should be handled by more than one object. Don't know which object should handle a request, probably more than one object will handle it automatically. Reduce coupling. Flexible in handling a request. Related patterns include o Composite, which a chain of responsibility pattern is often applied in conjunction with.

Example

The Java Servlet filter framework is an example of chain of resposibility design. Note that the chain.doFilter() is the method that should be called to make the chain roll. If the subclass missed it, the whole chain would be stopped or blocked. Java exception handling is another example of chain of responsibility design. When an error occurs, the exception call will look for a handling class. If there is no handler, the super Exception class will be called to throw the exception. Otherwise, the handler class will handle it.

Here comes a simple example, just to show how chain of responsibility works. Whenever you spend company's money, you need get approval from your boss, or your boss's boss. Let's say, the leadership chain is: Manager-->Director-->Vice President-->President

The following is a command line program to check who is responsible to approve your expenditure. import java.io.*; abstract class PurchasePower { protected final double base = 500; protected PurchasePower successor; public void setSuccessor(PurchasePower successor){ this.successor = successor; } }

abstract public void processRequest(PurchaseRequest request);

class Manager extends PurchasePower { private final double ALLOWABLE = 10 * base; public void processRequest(PurchaseRequest request ) { if( request.getAmount() < ALLOWABLE ) System.out.println("Manager will approve $"+ request.getAmount()); else if( successor != null) successor.processRequest(request); } } class Director extends PurchasePower { private final double ALLOWABLE = 20 * base; public void processRequest(PurchaseRequest request ) { if( request.getAmount() < ALLOWABLE ) System.out.println("Director will approve $"+ request.getAmount());

}

else if( successor != null) successor.processRequest(request);

} class VicePresident extends PurchasePower { private final double ALLOWABLE = 40 * base; public void processRequest(PurchaseRequest request) { if( request.getAmount() < ALLOWABLE ) System.out.println("Vice President will approve $" + request.getAmount()); else if( successor != null ) successor.processRequest(request); } } class President extends PurchasePower { private final double ALLOWABLE = 60 * base; public void processRequest(PurchaseRequest request){ if( request.getAmount() < ALLOWABLE ) System.out.println("President will approve $" + request.getAmount()); else System.out.println( "Your request for $" + request.getAmount() + " needs a board meeting!"); } } class PurchaseRequest { private int number; private double amount; private String purpose; public PurchaseRequest(int number, double amount, String purpose){ this.number = number; this.amount = amount; this.purpose = purpose; } public double getAmount() { return amount; } public void setAmount(double amt){ amount = amt; } public String getPurpose() { return purpose; } public void setPurpose(String reason) { purpose = reason; }

public int getNumber(){ return number; } public void setNumber(int num) { number = num; }

}

class CheckAuthority { public static void main(String[] args) throws Exception{ Manager manager = new Manager(); Director director = new Director(); VicePresident vp = new VicePresident(); President president = new President(); manager.setSuccessor(director); director.setSuccessor(vp); vp.setSuccessor(president); //enter ctrl+c to kill. while (true) { System.out.println("Enter the amount to check who should approve your expenditure."); System.out.print(">"); double d = Double.parseDouble(new BufferedReader(new InputStreamReader(System.in)).readLine()); manager.processRequest(new PurchaseRequest(0, d, "General")); } }

}

C:\ Command Prompt C:\> javac CheckAuthority.java C:\> java CheckAuthority Enter the amount to check who should approve your expenditure. >500 Manager will approve $500.0 Enter the amount to check who should approve your expenditure. >5000 Director will approve $5000.0 Enter the amount to check who should approve your expenditure. >11000 Vice President will approve $11000.0 Enter the amount to check who should approve your expenditure. >30000 Your request for $30000.0 needs a board meeting! Enter the amount to check who should approve your expenditure. >20000 President will approve $20000.0 Enter the amount to check who should approve your expenditure. > C:\>

You may redo it using interface instead of abstract class. The composite pattern is often used with chain of responsibility. That means a class may contain the related class that may handle the request.

Command Definition Streamlize objects by providing an interface to encapsulate a request and make the interface implemented by subclasses in order to parameterize the clients.

Where to use & benefits • • •

One action can be represented in many ways, like drop-down menu, buttons and popup menu. Need a callback function, i.e., register it somewhere to be called later. Specify and execute the request at different time

• • • •

Need to undo an action by storing its states for later retrieving. Decouple the object with its trigger Easily to be extensible by not touching the old structure. Related patterns include o Composite, which aggregates an object. You may combine it into a composite command pattern. In general, a composite command is an instance of the composite. o Memento, which keeps state of an object. Command supports undo and redo.

Example The simple example of Command pattern is to design a Command interface and with an execute method like this: public interface Command { public void execute(); }

Then, design multiple implementation classes and see how powerful the execute() method has been called dynamically. In order to take advantage of Java built-in interfaces, we will design a window with a drop down menu, button commands and popup menu with command pattern. As we know, JButton, JMenuItem and JPopupMenu have constructors accept Action type variable. Action interface extends ActionListener, which has the following hierarchy. public interface EventLister { ... } public interface ActionListener extends EventListener { ... } public interface Action extends ActionListener { ... }

There is an abstract class called AbstractAction which implements Action interface. It has the following design. public abstract class AbstractAction extends Object implements Action, Cloneable, Serializable

We will create several command classes to subclass the AbstractAction class and pass them to the constructors of JButton, JMenuItem and JPopupMenu classes. There is a

request method called actionPerformed(), every command classes must implement it in order to make it work. To show the concept, we just design two actions: submit and exit. You may expand such design to your need in your future project. Such action can be attached to any component, AWT or Swing. The caption, and Icon have been designed as well as tooltips. class ExitAction extends AbstractAction { private Component target; public ExitAction(String name, Icon icon, Component t){ putValue(Action.NAME, name); putValue(Action.SMALL_ICON, icon); putValue(Action.SHORT_DESCRIPTION, name + " the program"); target = t; } public void actionPerformed(ActionEvent evt) { int answer = JOptionPane.showConfirmDialog(target, "Are you sure you want to exit? ", "Confirmation", JOptionPane.YES_NO_OPTION); if ( answer == JOptionPane.YES_OPTION) { System.exit(0); } } }

Similar to the above exit action, the submit action is as follows: class SubmitAction extends AbstractAction { private Component target; public SubmitAction(String name, Icon icon, Component t){ putValue(Action.NAME, name); putValue(Action.SMALL_ICON, icon); putValue(Action.SHORT_DESCRIPTION, name + " the program"); target = t; } public void actionPerformed(ActionEvent evt) { JOptionPane.showMessageDialog(target, "submit action clicked "); } }

You can modify the program to add more commands in. These command classes are decoupled from any program. It is very good for maintenance. The whole workable program is as follows. You can run it to see the powerful command design pattern. import javax.swing.*; import java.awt.event.*; import java.awt.*; class ExitAction extends AbstractAction { private Component target;

public ExitAction(String name, Icon icon, Component t){ putValue(Action.NAME, name); putValue(Action.SMALL_ICON, icon); putValue(Action.SHORT_DESCRIPTION, name + " the program"); target = t; } public void actionPerformed(ActionEvent evt) { int answer = JOptionPane.showConfirmDialog(target, "Are you sure you want to exit? ", "Confirmation", JOptionPane.YES_NO_OPTION); if ( answer == JOptionPane.YES_OPTION) { System.exit(0); } } } class SubmitAction extends AbstractAction { private Component target; public SubmitAction(String name, Icon icon, Component t){ putValue(Action.NAME, name); putValue(Action.SMALL_ICON, icon); putValue(Action.SHORT_DESCRIPTION, name + " the program"); target = t; } public void actionPerformed(ActionEvent evt) { JOptionPane.showMessageDialog(target, "submit action clicked "); } } class Test extends JFrame{ Test() { Action ea = new ExitAction("Exit", null, this); Action sa = new SubmitAction("Submit", null, this); JMenuBar jbr = new JMenuBar(); JMenu dropmenu= new JMenu("File"); JMenuItem submitmenu = new JMenuItem(sa); JMenuItem exitmenu = new JMenuItem(ea); dropmenu.add(submitmenu); dropmenu.add(exitmenu); jbr.add(dropmenu); setJMenuBar(jbr); final JPopupMenu pop = new JPopupMenu("PopMenu"); pop.add(sa); pop.add(ea); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { showPopup(e); } public void mouseReleased(MouseEvent e) { showPopup(e); } private void showPopup(MouseEvent e) { if (e.isPopupTrigger()) {

pop.show(e.getComponent(), e.getX(), e.getY()); }

}

}); JPanel jp = new JPanel(); JButton subbtn = new JButton(sa); JButton exitbtn = new JButton(ea); jp.add(subbtn); jp.add(exitbtn); Container con = getContentPane(); con.add(jp, "South"); setTitle("Command pattern example"); setSize(400,200); setVisible(true); } public static void main(String[] args) { new Test(); }

} java Test

A windows pops up.

Pay attention to the action buttons. The instances can be parameterized to JButton, JMenuItem and JPopupMenu constructors. The powerful action design (Java built-in Action interface) makes objects like ExitAction, SubmitAction be used everywhere. Design once, use everywhere

Interpreter Definition Provides a definition of a macro language or syntax and parsing into objects in a program.

Where to use & benefits • • • •

Need your own parser generator. Translate a specific expression. Handle a tree-related information. Related patterns include o Composite, which is an instance in an interpreter. o Flyweight, which shows how to share symbols with abstract context.

o o

Iterator, which is used to traverse the tree structure. Visitor, which is used to maintain behavior of each note in tree structure.

Example Given any string expression and a token, filter out the information you want. The below is a simple parser program. the myParser method can be used to parse any expression. The composite, visit and iterator patterns have been used. import java.util.*; class Parser{ private String expression; private String token; private List result; private String interpreted; public Parser(String e, String t) { expression = e; token = t; } public void myParser() { StringTokenizer holder = new StringTokenizer(expression, token); String[] toBeMatched = new String[holder.countTokens()]; int idx = 0; while(holder.hasMoreTokens()) { String item = holder.nextToken(); int start = item.indexOf(","); if(start==0) { item = item.substring(2); } toBeMatched[idx] = item; idx ++; } result = Arrays.asList(toBeMatched); } public List getParseResult() { return result; } public void interpret() { StringBuffer buffer = new StringBuffer(); ListIterator list = result.listIterator(); while (list.hasNext()){ String token = (String)list.next(); if (token.equals("SFO")){ token = "San Francisco"; }else if(token.equals("CA")) { token = "Canada"; } //... buffer.append(" " + token); } interpreted = buffer.toString();

} public String getInterpretedResult() { return interpreted; } public static void main(String[] args) { String source = "dest='SFO',origin='CA',day='MON'"; String delimiter = "=,'"; Parser parser = new Parser(source, delimiter); parser.myParser(); parser.interpret(); String result = parser.getInterpretedResult(); System.out.println(result); }

} java Parser dest San Francisco origin Canada day MON

Iterator Definition Provide a way to move through a list of collection or aggregated objects without knowing its internal representations.

Where to use & benefits • • • • • •

Use a standard interface to represent data objects. Use s standard iterator built in each standard collection, like List, Sort, or Map. Need to distinguish variations in the traversal of an aggregate. Similar to Enumeration class, but more effective. Need to filter out some info from an aggregated collection. Related patterns include o Composite, which supports recursive structures, whereas an iterator is often applied on it. o Factory Method, which provides appropriate instances needed by an iterator subclasses. o Memento, which is often used with an Iterator. The iterator stores the memento internally.

Example Employee is an interface, Manager, PieceWorker, HourlyWorker and CommissionWorker are implementation classes of interface Employee. EmployeeTest class will create a list and use a built-in iterator of ArrayList class to traverse the members of the list.

import java.util.*; interface Employee { public abstract double earnings(); } class Manager implements Employee { private double weeklySalary; private String name; public Manager(String name, double s) { this.name = name; setWeeklySalary(s); } void setWeeklySalary(double s) { if (s > 0) { weeklySalary = s; } else weeklySalary = 0; } public double earnings() { return weeklySalary; } public String getName() { return name; } public String toString() { return "Manager: " + getName(); } } class PieceWorker implements Employee { private double wagePerPiece; private int quantity; private String name; public PieceWorker(String name, double w, int q) { this.name = name; setWagePerPiece(w); setQuantity(q); } void setWagePerPiece(double w) { if (w > 0) wagePerPiece = w; else wagePerPiece = 0; } void setQuantity(int q) { if ( q > 0) quantity = q; else quantity = 0; } public String getName() { return name; } public double earnings() {

}

return quantity * wagePerPiece;

public String toString() { return "Piece worker: " + getName(); } } class HourlyWorker implements Employee { private double hourlyWage; private double hours; private String name; public HourlyWorker(String name, double w, double h) { this.name = name; setHourlyWage(w); setHours(h); } void setHourlyWage(double w) { if (w > 0) hourlyWage = w; else hourlyWage = 0; } void setHours(double h) { if ( 0 <= h && h < 168) hours = h; else hours = 0; } public String getName() { return name; } public double earnings() { return hourlyWage * hours; } public String toString() { return "Hourly worker: " + getName(); } } class CommissionWorker implements Employee { private double salary; private double commission; private double totalSales; private String name; public CommissionWorker(String name, double salary, double commission, double totalSales) { this.name = name; setSalary(salary); setCommission(commission); setTotalSales(totalSales); } void setSalary(double s) { if( s > 0) salary = s;

else

}

salary = 0; } void setCommission(double c) { if ( c > 0) commission = c; else commission = 0; } void setTotalSales(double ts) { if (ts > 0 ) totalSales = ts; else totalSales = 0; } public String getName() { return name; } public double earnings() { return salary + commission/100*totalSales; } public String toString() { return "Commission worker:" + getName(); }

class EmployeeTest { public static void main(String[] args) { java.util.List list = new ArrayList(); list.add(new Manager("Bill", 800.00)); list.add(new CommissionWorker("Newt", 400.0, 3.75, 159.99)); list.add(new PieceWorker("Al", 2.5, 200)); list.add(new HourlyWorker("Babara", 13.75, 40)); list.add(new Manager("Peter", 1200.00)); list.add(new CommissionWorker("Margret", 600.0,5.5, 200.25)); list.add(new PieceWorker("Mark", 4.5, 333)); list.add(new HourlyWorker("William", 31.25, 50)); System.out.println("Use built-in iterator:"); Iterator iterator = list.iterator(); while(iterator.hasNext()) { Employee em = (Employee)iterator.next(); System.out.print(em + " earns $"); System.out.println(em.earnings()); } } } %java EmployeeTest Use built-in iterator: Manager: Bill earns $800.0 Commission worker:Newt earns $405.999625 Piece worker: Al earns $500.0 Hourly worker: Babara earns $550.0 Manager: Peter earns $1200.0 Commission worker:Margret earns $611.01375 Piece worker: Mark earns $1498.5

Hourly worker: William earns $1562.5

The above example also shows a dynamic binding feature which is popular in ObjectOriented realm. If you want to pick up a specific object from the aggregated list, you may use the following code. while(iterator.hasNext()) { Employee em = (Employee)iterator.next(); if (em instanceof Manager) { System.out.print(em + " earns $"); System.out.println(em.earnings()); } }

The above list can also be replaced by an array and achieve the same result.

Mediator Definition Define an object that encapsulates details and other objects interact with such object. The relationships are loosely decoupled.

Where to use & benefits • • • • • • • •

Partition a system into pieces or small objects. Centralize control to manipulate participating objects(a.k.a colleagues) Clarify the complex relationship by providing a board committee. Limit subclasses. Improve objects reusabilities. Simplify object protocols. The relationship between the control class and other participating classes is multidirectional. Related patterns include o Facade, which abstracts a subsystem to provide a more convenient interface, and its protocol is unidirectional, whereas a mediator enables cooperative behavior and its protocol is multidirectional. o Command, which is used to coordinate functionality. o Observer, which is used in mediator pattern to enhance communication.

Example

If you have a complex GUI, whenever a button has been clicked, the related actions should be disabled or enabled. You may design a Mediator class to include all related classes: interface Command { void execute(); } class Mediator { BtnView btnView; BtnSearch btnSearch; BtnBook btnBook; LblDisplay show;; //.... void registerView(BtnView v) { btnView = v; } void registerSearch(BtnSearch s) { btnSearch = s; } void registerBook(BtnBook b) { btnBook = b; } void registerDisplay(LblDisplay d) { show = d; } void book() { btnBook.setEnabled(false); btnView.setEnabled(true); btnSearch.setEnabled(true); show.setText("booking..."); } void view() { btnView.setEnabled(false); btnSearch.setEnabled(true); btnBook.setEnabled(true); show.setText("viewing..."); } void search() { btnSearch.setEnabled(false); btnView.setEnabled(true); btnBook.setEnabled(true); show.setText("searching..."); } }

Then, you may define classes which should be controlled by the Mediator class. class BtnView extends JButton implements Command { Mediator med; BtnView(ActionListener al, Mediator m) { super("View"); addActionListener(al); med = m; med.registerView(this); }

}

public void execute() { med.view(); }

class BtnSearch extends JButton implements Command { Mediator med; BtnSearch(ActionListener al, Mediator m) { super("Search"); addActionListener(al); med = m; med.registerSearch(this); } public void execute() { med.search(); } } class BtnBook extends JButton implements Command { Mediator med; BtnBook (ActionListener al, Mediator m) { super("Book"); addActionListener(al); med = m; med.registerBook(this); } public void execute() { med.book(); } } class LblDisplay extends JLabel{ Mediator med; LblDisplay (Mediator m) { super("Just start..."); med = m; med.registerDisplay(this); setFont(new Font("Arial",Font.BOLD,24)); } }

From the above design, you can see that the relationships among the classes, which also known as collegues or participating classes, are multidirectional. Mediator class contains all the information about these classes and knows what these classes are going to do. The participating classes have to register themselves to the Mediator class. The MediatorDemo class will show the cooperation among the classes. class MediatorDemo extends JFrame implements ActionListener { Mediator med = new Mediator(); MediatorDemo() { JPanel p = new JPanel(); p.add(new BtnView(this,med)); p.add(new BtnBook(this,med)); p.add(new BtnSearch(this, med));

getContentPane().add(new LblDisplay(med), "North"); getContentPane().add(p, "South"); setSize(400,200); setVisible(true);

}

} public void actionPerformed(ActionEvent ae) { Command comd = (Command)ae.getSource(); comd.execute(); } public static void main(String[] args) { new MediatorDemo(); }

The following is a complete code for the above program. interface Command { void execute(); } class Mediator { BtnView btnView; BtnSearch btnSearch; BtnBook btnBook; LblDisplay show;; //.... void registerView(BtnView v) { btnView = v; } void registerSearch(BtnSearch s) { btnSearch = s; } void registerBook(BtnBook b) { btnBook = b; } void registerDisplay(LblDisplay d) { show = d; } void book() { btnBook.setEnabled(false); btnView.setEnabled(true); btnSearch.setEnabled(true); show.setText("booking..."); } void view() { btnView.setEnabled(false); btnSearch.setEnabled(true); btnBook.setEnabled(true); show.setText("viewing..."); } void search() { btnSearch.setEnabled(false); btnView.setEnabled(true); btnBook.setEnabled(true); show.setText("searching..."); }

} class BtnView extends JButton implements Command { Mediator med; BtnView(ActionListener al, Mediator m) { super("View"); addActionListener(al); med = m; med.registerView(this); } public void execute() { med.view(); } } class BtnSearch extends JButton implements Command { Mediator med; BtnSearch(ActionListener al, Mediator m) { super("Search"); addActionListener(al); med = m; med.registerSearch(this); } public void execute() { med.search(); } } class BtnBook extends JButton implements Command { Mediator med; BtnBook (ActionListener al, Mediator m) { super("Book"); addActionListener(al); med = m; med.registerBook(this); } public void execute() { med.book(); } } class LblDisplay extends JLabel{ Mediator med; LblDisplay (Mediator m) { super("Just start..."); med = m; med.registerDisplay(this); setFont(new Font("Arial",Font.BOLD,24)); } } class MediatorDemo extends JFrame implements ActionListener { Mediator med = new Mediator(); MediatorDemo() { JPanel p = new JPanel(); p.add(new BtnView(this,med)); p.add(new BtnBook(this,med)); p.add(new BtnSearch(this, med)); getContentPane().add(new LblDisplay(med), "North");

getContentPane().add(p, "South"); setSize(400,200); setVisible(true); } public void actionPerformed(ActionEvent ae) { Command comd = (Command)ae.getSource(); comd.execute(); } public static void main(String[] args) { new MediatorDemo(); } } java MediatorDemo A window will pop up. Try the features.

Memento Definition To record an object internal state without violating encapsulation and reclaim it later without knowledge of the original object.

Where to use & benefits • • • • •

Let some info in an object to be available by another object by using default access control. Save some info for later uses. Need undo/redo features. Used in database transaction. Related patterns include o Command, which supports undo or redo features, whereas a memento keeps state of an object. o Iterator, which provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation, whereas a memento can be used for iteration.

Example To design a program with Memento feature is used to combine several design patterns like Command, Mediator or Iterator. Here is an example expanded from Mediator example.

To show the Memento design concept, we record a dice number. This is very simple program. The Memento class just holds a number. class Memento { int num; Memento(int c) { num = c; } int getNum() { return num; } }

Then we combine Mediator and Command patterns to design three buttons and one label.The first button throws dice, the second button shows the dice number backward, and the third button clears number displayed. The label is used to display the dice number thrown. We use Math.random() method to get number from 1 to 6. class BtnDice extends JButton implements Command { Mediator med; BtnDice(ActionListener al, Mediator m) { super("Throw Dice"); addActionListener(al); med = m; med.registerDice(this); } public void execute() { med.throwit(); } } class BtnClear extends JButton implements Command { Mediator med; BtnClear(ActionListener al, Mediator m) { super("Clear"); addActionListener(al); med = m; med.registerClear(this); } public void execute() { med.clear(); } } class BtnPrevious extends JButton implements Command { Mediator med; BtnPrevious(ActionListener al, Mediator m) { super("Previous"); addActionListener(al); med = m; med.registerPrevious(this); } public void execute() { med.previous(); } }

class LblDisplay extends JLabel{ Mediator med; LblDisplay (Mediator m) { super("0",JLabel.CENTER); med = m; med.registerDisplay(this); setBackground(Color.white); setBorder(new EtchedBorder(Color.blue, Color.green)); Font font = new Font("Arial",Font.BOLD,40); setFont(font); } }

The Mediator class will hold these participating objects and manipulate their relationships. class Mediator { BtnDice btnDice; BtnPrevious btnPrevious; BtnClear btnClear; LblDisplay show; java.util.List list, undo; boolean restart = true; int counter = 0, ct = 0; //.... Mediator() { list = new ArrayList(); undo = new ArrayList(); } void registerDice(BtnDice d) { btnDice = d; } void registerClear(BtnClear c) { btnClear = c; } void registerPrevious(BtnPrevious p) { btnPrevious = p; } void registerDisplay(LblDisplay d) { show = d; } void throwit() { show.setForeground(Color.black); int num = (int)(Math.random()*6 +1); int i = counter++; list.add(i, new Integer(num)); undo.add(i, new Memento(num)); show.setText(""+num); } void previous() { show.setForeground(Color.red); btnDice.setEnabled(false); if (undo.size() > 0) { ct = undo.size()-1; Memento num = (Memento)undo.get(ct);

show.setText(""+num.getNum()); undo.remove(ct); } if (undo.size() == 0) show.setText("0");

}

} void clear() { list = new ArrayList(); undo = new ArrayList(); counter = 0; show.setText("0"); btnDice.setEnabled(true); }

Finally, write a demo class. class MementoDemo extends JFrame implements ActionListener { Mediator med = new Mediator(); MementoDemo() { JPanel p = new JPanel(); p.add(new BtnDice(this,med)); p.add(new BtnPrevious(this,med)); p.add(new BtnClear(this,med)); JPanel dice = new JPanel(); LblDisplay lbl = new LblDisplay(med); dice.add(lbl); getContentPane().add(dice, "Center"); getContentPane().add(p, "South"); setTitle("Memento pattern example"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(400,200); setVisible(true); } public void actionPerformed(ActionEvent ae) { Command comd = (Command)ae.getSource(); comd.execute(); } public static void main(String[] args) { new MementoDemo(); } }

The complete workable program is as follows. Copy it, compile it and run it. import import import import import import

javax.swing.*; java.awt.event.*; java.awt.FontMetrics; java.awt.*; java.util.*; javax.swing.border.*;

interface Command { void execute(); }

class Mediator { BtnDice btnDice; BtnPrevious btnPrevious; BtnClear btnClear; LblDisplay show; java.util.List list, undo; boolean restart = true; int counter = 0, ct = 0; //.... Mediator() { list = new ArrayList(); undo = new ArrayList(); } void registerDice(BtnDice d) { btnDice = d; } void registerClear(BtnClear c) { btnClear = c; } void registerPrevious(BtnPrevious p) { btnPrevious = p; } void registerDisplay(LblDisplay d) { show = d; } void throwit() { show.setForeground(Color.black); int num = (int)(Math.random()*6 +1); int i = counter++; list.add(i, new Integer(num)); undo.add(i, new Memento(num)); show.setText(""+num); } void previous() { show.setForeground(Color.red); btnDice.setEnabled(false); if (undo.size() > 0) { ct = undo.size()-1; Memento num = (Memento)undo.get(ct); show.setText(""+num.getNum()); undo.remove(ct); } if (undo.size() == 0) show.setText("0"); } void clear() { list = new ArrayList(); undo = new ArrayList(); counter = 0; show.setText("0"); btnDice.setEnabled(true); } } class BtnDice extends JButton implements Command { Mediator med;

}

BtnDice(ActionListener al, Mediator m) { super("Throw Dice"); addActionListener(al); med = m; med.registerDice(this); } public void execute() { med.throwit(); }

class BtnClear extends JButton implements Command { Mediator med; BtnClear(ActionListener al, Mediator m) { super("Clear"); addActionListener(al); med = m; med.registerClear(this); } public void execute() { med.clear(); } } class BtnPrevious extends JButton implements Command { Mediator med; BtnPrevious(ActionListener al, Mediator m) { super("Previous"); addActionListener(al); med = m; med.registerPrevious(this); } public void execute() { med.previous(); } } class Memento { int num; Memento(int c) { num = c; } int getNum() { return num; } } class LblDisplay extends JLabel{ Mediator med; LblDisplay (Mediator m) { super("0",JLabel.CENTER); med = m; med.registerDisplay(this); setBackground(Color.white); setBorder(new EtchedBorder(Color.blue, Color.green)); Font font = new Font("Arial",Font.BOLD,40); setFont(font); } } class MementoDemo extends JFrame implements ActionListener {

Mediator med = new Mediator(); MementoDemo() { JPanel p = new JPanel(); p.add(new BtnDice(this,med)); p.add(new BtnPrevious(this,med)); p.add(new BtnClear(this,med)); JPanel dice = new JPanel(); LblDisplay lbl = new LblDisplay(med); dice.add(lbl); getContentPane().add(dice, "Center"); getContentPane().add(p, "South"); setTitle("Memento pattern example"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(400,200); setVisible(true); } public void actionPerformed(ActionEvent ae) { Command comd = (Command)ae.getSource(); comd.execute(); } public static void main(String[] args) { new MementoDemo(); }

}

Observer Definition One object changes state, all of its dependents are updated automatically.

Where to use & benefits • • • • • • •

One change affects one or many objects. Many object behavior depends on one object state. Need broadcast communication. AKA “Publish-Subscribe”. Maintain consistency between objects keep classes from becoming too tightly coupled, which would hamper reusability. Related patterns include o Singleton, which is used to make observable object unique and accessible globally. o Mediator, which is used to encapsulate updated objects.

Example

Observer pattern is often used in GUI application. For example, defining a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically, like stock change affecting many data or diagram updated accordingly. Java API provides a built-in interface Observer and class Observable for use. To show how observer pattern works, two windows have been created. One is for user input; another is for display. When the data has been entered in the textfield, another window gets the message and display it with a dialog. The private inner classes have been used in this example. import javax.swing.*; import java.awt.event.*; import java.util.*; class DisplayForm extends JFrame { InputFormObserver input = new InputFormObserver(); InputForm inputForm ; Observable obsInput; JTextField display; //... public DisplayForm() { addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }}); inputForm = new InputForm(); obsInput = inputForm.getInputInfo(); obsInput.addObserver(input); display = new JTextField(10); display.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } }); getContentPane().add(display); setTitle("Observer form"); setSize(200,100); setLocation(200,100); setVisible(true); } private class InputFormObserver implements Observer { public void update(Observable ob, Object o) { doSomeUpdate(); if (obsInput.countObservers()>0) obsInput.deleteObservers(); obsInput = inputForm.getInputInfo(); obsInput.addObserver(input); }

} public void doSomeUpdate() { display.setText(inputForm.getText()); JOptionPane.showMessageDialog(DisplayForm.this, "This form has been updated");

} public static void main(String args[]) { DisplayForm df = new DisplayForm(); }

} class InputForm extends JFrame { public InformDisplay inform = new InformDisplay(); //... JTextField input= new JTextField(10); public InputForm() { JPanel panel= new JPanel(); input.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { inform.notifyObservers(); } }); panel.add(new JLabel("Enter: ")); panel.add(input); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }}); getContentPane().add(panel); setTitle("Observable form"); setSize(200,100); setVisible(true); } public Observable getInputInfo() { return inform; } public String getText() { return input.getText(); } private class InformDisplay extends Observable { public void notifyObservers() { setChanged(); super.notifyObservers(); } public String getChange() { return input.getText(); } } //...

} java DisplayForm

Two windows will come up: one for user input, the other for observing user input. Enter data in the input window, a dialog box from other window shows up

and the input data has been shown in the other window.

State Definition An object's behavior change is represented by its member classes, which share the same super class.

Where to use & benefits • • • • • •

Need to control many states without using if-else or switch statements. Use a class to represent a state, not a constant or something else. Every state has to act in a similar manner. Every state must be a subclass of the same super class. Simplify and clarify the program. Related patterns include o Flyweight, which explains when and how a state object can be shared. o Singleton which is often used with state pattern to ensure some state change is shared with class itself, not instances of the class.

Example To show the concept of State pattern, we use a simple command line program. If a GUI program is used, a mediator pattern or a flyweight pattern may be applied on it. Users connect to a database to do some jobs. Users from Management department may focus on management. Users from Sales department may focus on sales information. Every connection has to perform similar functions like open, log and close. Suppose we have an abstract Connection class and have these functions listed. Thus, every subclass of Connection must implement these functions. We list three subclasses Management, Sales and Accounting for example, just to show the State pattern concept. The Controller class contains each state of connection. Its behavior is decided by another object, which is a Test class. All the details have been hidden from the Test class. Suppose we have a server which is a singleton. Which connection is made depends on the user. We use a Test class which makes a trigger from command line. In the real program, the trigger should be made by the user. The following is a skeleton program. abstract class Connection { public abstract void open(); public abstract void close();

public abstract void log(); } class Accounting extends Connection { public void open() { System.out.println("open database for accounting"); } public void close() { System.out.println("close the database"); } public void log() { System.out.println("log activities"); } //... } class Sales extends Connection { public void open() { System.out.println("open database for sales"); } public void close() { System.out.println("close the database"); } public void log() { System.out.println("log activities"); } public void update() { // } } class Management extends Connection { public void open() { System.out.println("open database for management"); } public void close() { System.out.println("close the database"); } public void log() { System.out.println("log activities"); } //... } class Controller { public static Accounting acct; public static Sales sales; public static Management manage; private static Connection current; Controller() { acct = new Accounting(); sales = new Sales(); manage = new Management(); } public void makeAccountingConnection() { current = acct; } public void makeSalesConnection() { current = sales; }

public void makeManagementConnection() { current = manage; } public void open() { current.open(); } public void close() { current.close(); } public void log() { current.log(); } } class Test { String con; Controller controller; Test(String con) { controller = new Controller(); //the following trigger should be made by the user if(con.equalsIgnoreCase("management")) controller.makeManagementConnection(); if(con.equalsIgnoreCase("sales")) controller.makeSalesConnection(); if(con.equalsIgnoreCase("accounting")) controller.makeAccountingConnection(); controller.open(); controller.log(); controller.close(); } } class Server { public static Test test; public static void main(String[] args) { new Test(args[0]); } }

When we run the program with different connection, we will invoke the program in the following printout: %java Server management open database for management log activities close the database %java Server accounting open database for accounting log activities close the database %java Server sales open database for sales log activities close the database

Strategy Definition Group several algorithms in a single module to provide alternatives. Also known as policy.

Where to use & benefits • • • • • • • • •

Encapsulate various algorithms to do more or less the same thing. Need one of several algorithms dynamically. The algorithms are exchangeable and vary independently Configure a class with one of many related classes (behaviors). Avoid exposing complex and algorithm-specific structures. Data is transparent to the clients. Reduce multiple conditional statements. Provide an alternative to subclassing. Related patterns include State, which can activate several states, whereas a strategy can only activate one of the algorithms. o o o

Flyweight, which provides a shared object that can be used in multiple contexts simultaneously, whereas a strategy focuses on one context. Decorator, which changes the skin of an object, whereas a strategy changes the guts of an object. Composite, which is used to combine with a strategy to improve efficiency.

Example Compress files using different algorithms or save files in different formats or draw graphic in different presentations. Here is a simple example. Just to show the concept of a strategy pattern. interface FortuneCookies { public void print(); } class Five implements FortuneCookies { public void print() { System.out.println("It is your turn to get it"); } } class Two implements FortuneCookies {

public void print() { System.out.println("It is never too late to start"); }

} class Null implements FortuneCookies { public void print() { System.out.println("You got nothing"); } } class Dice { public int throwIt() { return (int)(Math.random()*6)+1; } } //more class... class Test { static void goodFortune() { int luckyNum = new Dice().throwIt(); FortuneCookies fc; switch (luckyNum) { case 2: fc = new Two(); break; case 5: fc = new Five(); break; //more default: fc = new Null(); } fc.print(); } public static void main(String[] args) { goodFortune(); } }

Template Method Definition Provide an abstract definition for a method or a class and redefine its behavior later or on the fly without changing its structure.

Where to use & benefits • • • • • •

To make many similar operations template. From many specialized operations to a generalized operation. Refactor common behavior to simplify code. Algorithm related improvement. Need good coding skill to conquer it. May be hard to read for novice.

• •

Easy to produce ambiguity if not written well. Related patterns include o Factory Method, which is combined with template method. o Strategy, which is used to delegate or coordinate the template method.

Examples For example, a loan application process may take several steps to finish. Let's assume the steps are as follows: • • • • • •

check client's bank balance history check client's credit score from three different companies check client's other loan information check client's stock holding value check client's income potential in the future etc.

You may use a template method to hold the process steps together without considering the real implementation in the subclass. abstract class CheckBackground { public public public public public

abstract abstract abstract abstract abstract

void void void void void

checkBank(); checkCredit(); checkLoan(); checkStock(); checkIncome();

//work as template method public void check() { checkBank(); checkCredit(); checkLoan(); checkStock(); checkIncome(); } } class LoanApp extends CheckBackground { private String name; public LoanApp(String name) { this.name = name; } public String getName() { return name; } public void checkBank() { //ck acct, balance

}

System.out.println("check bank...");

public void checkCredit() { //ck score from 3 companies System.out.println("check credit..."); } public void checkLoan() { //ck other loan info System.out.println("check other loan..."); } public void checkStock() { //ck how many stock values System.out.println("check stock values..."); } public void checkIncome() { //ck how much a family make System.out.println("check family income..."); } //other methods } class TestTemplate { public static void main(String[] args) { LoanApp mortgageClient = new LoanApp("Judy"); System.out.println("\nCheck client " + mortgageClient.getName()+ " Mortgage loan application. "); mortgageClient.check(); LoanApp equityloanClient = new LoanApp("Mark"); System.out.println("\nCheck client " + equityloanClient.getName()+ " equity loan application. "); equityloanClient.check(); } }

C:\ Command Prompt C:\> javac TestTemplate.java C:\> java TestTemplate Check check check check check check

client Judy Mortgage loan application. bank... credit... other loan... stock values... family income...

Check check check check check check

client Mark equity loan application. bank... credit... other loan... stock values... family income...

C:\>

Method overloading and method overriding are good examples of template method pattern. For example, • • •

Coercion polymorphism -- refers to a single operation serving several types through implicit type conversion. Overloading polymorphism -- refers to using a single identifier for different operations. Parametric polymorphism -- refers to a class declaration that allows the same field names and method signatures to associate with a different type in each instance of that class.

The add() in the following code example is a template method. It can take any numerical primitive types and the result can be casted to the type you want. //coercion polymorphism abstract class Add { public abstract double add(double d1, double d2);//template } class AddAnyTypeNumber extends Add{ public double add(double d1, double d2) { return d1 + d2; } } class Test { public static void main(String[] args) { double d1 = 10.5, d2 = 9.5; float f1 = 11.5f, f2 = 12.5f; long l1 = 1, l2 = 2; int i1 = 3, i2 = 4; short s1 = 7, s2 = 8; byte b1 = 5, b2 = 6;

AddAnyTypeNumber addNumber = new AddAnyTypeNumber(); System.out.println(addNumber.add(d1,d2)); System.out.println((float)addNumber.add(f1,f2)); System.out.println((long)addNumber.add(l1,l2)); System.out.println((int)addNumber.add(i1,i2)); System.out.println((short)addNumber.add(s1,s2)); System.out.println((byte)addNumber.add(b1,b2)); }

}

C:\ Command Prompt C:\> java Test 20.0 24.0 3 7 15 11 Note that the side effect of using coercion polymorphism is casting in and casting out if you need specific type to do the work. If you forget to do so, you may have unexpected result and it is hard to debug. If you don't have template method pattern concept or don't know Java type promotion technique, you may write code in the following way: abstract class Add { public abstract double add(double d1, double d2); public abstract float add(float d1, float d2); public abstract long add(long d1, long d2); public abstract int add(int d1, int d2); public abstract short add(short d1, short d2); public abstract byte add(byte d1, byte d2); } class AddNumber extends Add{ public double add(double d1, double d2) { return d1 + d2; } public float add(float f1, float f2) { return f1 + f2; } public long add(long l1, long l2) { return l1 + l2; } public int add(int i1, int i2) { return i1 + i2; } public short add(short s1, short s2) { return (short)(s1 + s2); } public byte add(byte b1, byte b2) { return (byte)(b1 + b2); } }

class Test { public static void main(String[] args) { double d1 = 10.5, d2 = 9.5; float f1 = 11.5f, f2 = 12.5f; long l1 = 1, l2 = 2; int i1 = 3, i2 = 4; short s1 = 7, s2 = 8; byte b1 = 5, b2 = 6; AddNumber addNumber = new AddNumber();

}

System.out.println(addNumber.add(d1,d2)); System.out.println(addNumber.add(f1,f2)); System.out.println(addNumber.add(l1,l2)); System.out.println(addNumber.add(i1,i2)); System.out.println(addNumber.add(s1,s2)); System.out.println(addNumber.add(b1,b2));

}

C:\ Command Prompt C:\> java Test 20.0 24.0 3 7 15 11 Without using template method pattern, you may write more lines of code. The good thing is that you don't have any side effect by using specific designed method and you don't need to cast in or out.

Visitor Definition Define a new operation to deal with the classes of the elements without changing their structures.

Where to use & benefits • • • • •

Add operations on a bunch of classes which have different interfaces. Traverse the object structure to gather related operations Easy to add new operations. Crossing class hierarchies may break encapsulation. Related patterns include o Composite, which may be applied in a visitor pattern.

o

Interpreter, which may be used to go through structure and define new operation in a visitor pattern.

Example The following is a dummy program. Two interfaces involved: Visitor and Pizza. The Pizza system is completely independent. "How to get it" tries to add new operations to the Pizza system. It is done by adding another interface Visitor and parameterizing Pizza interface in the abstract method visit(composite pattern). The "how to get" classes implement Visitor interface and make a connection with Pizza system. import java.util.*; interface Visitor { public void visit(Pizza p); } interface Pizza { public String order(); } class PopJohn implements Pizza { final String name = "PopJohn"; public String order() { return name; } } class PizzaHut implements Pizza { final String name = "PizzaHut"; public String order() { return name; } } class GodFather implements Pizza { final String name = "GodFather"; public String order() { return name; } } class ByPickup implements Visitor { private String name; private final String method = "By pick up"; public void visit(Pizza p) { name = p.order(); } public String toString() { return name + " " + method; }

} class ByEatin implements Visitor { private String name; private final String method = "By eat in"; public void visit(Pizza p) { name = p.order(); }

public String toString() { return name + " " + method; } } class ByDelivery implements Visitor { private String name; private final String method = "By delivery"; public void visit(Pizza p) { name = p.order(); } public String toString() { return name + " " + method; } } class Dinner { public Pizza getDinner() { switch ((int)(Math.random()*3)){ case 0: return new PopJohn(); case 1: return new PizzaHut(); case 2: return new GodFather(); default: return null; } } public Visitor howto() { switch ((int)(Math.random()*3)){ case 0: return new ByPickup(); case 1: return new ByEatin(); case 2: return new ByDelivery(); default: return null; } } } class Test { public static void main(String[] args) { List pizzaList = new ArrayList(); pizzaList.add(new PopJohn()); pizzaList.add(new PizzaHut()); pizzaList.add(new GodFather()); Iterator it = pizzaList.iterator(); System.out.println("How many pizza restaurants in this area?"); while (it.hasNext()) { System.out.println(((Pizza)it.next()).order()); } Dinner d = new Dinner(); Pizza pza = d.getDinner(); Visitor v = d.howto(); v.visit(pza); System.out.println("\nWhich store for dinner?"); System.out.println(v); } } //run it several times. java Test

How many pizza restaurants in this area? PopJohn PizzaHut GodFather Which restaurant for dinner? GodFather By delivery java Test How many pizza restaurants in this area? PopJohn PizzaHut GodFather Which restaurant for dinner? PizzaHut By pick up java Test How many pizza restaurants in this area? PopJohn PizzaHut GodFather Which restaurant for dinner? PizzaHut By delivery

J2EE Patterns

MVC Definition The Model/View/Controller(MVC) is an architecture design pattern. Model means data, View means representation and Controller works on data and representation. MVC focuses on decouple the triad relationships among data, representation and controller.

Where to use & benefits • • • • • •

Application architecture design. Any data related design, including non-visual application. Decouple complex object to improve maintainability. Increase object reusability. Achieve design flexibility. Related patterns include o Almost all patterns can be used with MVC.

History The Model/View/Controller(MVC) originates from Smalltalk, an OO programming language.

Core issue MVC consists of three kind of objects. The Model is an internal representation of the data, the View is the screen presentation of GUI, and the Controller coordinates changes between the Model and View.

SCJD project design To achieve the MVC architecture in your project, you have to decouple View and Model by Controller. Your GUI as View should be designed as a module. It can be launched separately. Your data related classes as Model should be treated as a module too. Your controller classes should response to any data change on the GUI. Such design will increase reusability and flexibility. Try to visualize that the user reacts with the GUI, a DataManager(Controller) listens to the GUI's call. If the user needs to load data, such request is sent to the DataManager, the DataManager starts loading, searching and extracting the requested data from the server and sends it back to the GUI. GUI is responsible to display data. Here the server acts as Model, the DataManager acts as Controller and GUI acts as View. The DataManager can be used for both remote and local modes (design two constructors for both modes), the GUI can be replaced with any design and the data related classes can be packaged together and put on local and server sides. All of the three objects can be reused for other projects with little code alteration. If you grasp such concept and skill, you will save a lot of time in designing and developing your projects in the future. This is the so-called OOA/OOD.

Business Delegate Definition An intermediate class decouples between presentation-tier clients and business services.

Where to use & benefits •

Simplify the complicated relationship.

• • • • •

Reduce coupling. Cache results and references to remote business services. Cut potentially costly round trips Hide the underlying implementation details of business service. Related patterns include o Proxy combined to simplify the complexity.

Example Make a class deal with lookups and exception, acting as a representative of the client components

Composite Entity Definition Use a coarse-grained interface to manage interactions between fine-grained or coarsegrained and dependent objects internally. The Composite Entity is a coarse-grained entity bean. It may be the coarse-grained object or hold a reference to the coarse-grained object. Also known as Aggregate Entity.

Where to use & benefits • • • • • • • • • • • • •

Combine coarse-grained object and its related dependent objects into a single entity bean. Multiple clients share persistent objects. Model a network of related business entities. In both local and distributed environment, use remote entity beans to model dependent business objects or fine-grained objects. Improve performance by eliminating the parameter and return value serialization and data transmission costs. Eliminate inter-entity relationships Improve manageability by reducing entity beans. Improve network performance Reduce database schema dependency Increase object granularity Facilitate composite transer object creation. Overhead of multi-level dependent object graphs. Related patterns include o Transfer Object used to return to client and also used to serialize the coarse-grained and dependent objects tree, or part of the tree, as required. o Session Facade used to manage the inter-entity-bean relationships.

Example

Data Access Object Definition Adapt a uniform interface to access multiple databases like relational, unrelational, object-oriented, etc.

Where to use & benefits • • • • • • • • •

Need to access multiple data sources like legacy systems, B2B, LDAP, and so forth. Lack of uniform APIs to address the requirements to access disparate systems. Persistent storage APIs vary depending on the product vendor. Adapt and encapsulate all access to the data source. Hide the data source implementation details from its clients. More portable and less code dependencies in components. Solve differences in the APIs which is used to access different persistent storage mechanisms. Not useful for container-managed persistence. Related patterns include o factory method -- used to deal with different data sources. o abstract factory -- used to make an abstract layer of access to data sources. o transfer object -- used to transport data to and from its clients.

Example

Front Controller Definition Using a single component to process application requests.

Where to use & benefits • • •

JSP or Servlet. Design request handling component. Channel all requests through a single controller.

• • • • • •

Centralize request processing and view selection. Reduce business logic in a view Improve manageability of security Promote code reuse across requests Avoid code duplication Related patterns include o Command combined with multiple requests. o Intercepting Filter both centralize control of certain types of request processing. o Page Controller -- an alternative way.

Example Design a servlet to deal with all the requests.

Intercepting Filter Definition A pluggable component design to intercept incomming requests and outgoing responses, provide common services in a standard manner (independently) without changing core processing code.

Where to use & benefits • • • • • • • • • • • • • •

Logging and authentication. Enhance security. Add additional function to existing web application. Decorate main process. Debug. Pre-processing or post-processing for specific clients. Uncompress incoming request. Convert input encoding schema. Being added or removed transparently or declaratively and triggered automatically Improve reusability Deployment-time composability Each filter is loosely coupled Inefficient for information sharing. Related patterns include o Front Control better suited to handling core processing. o Template good for template filter strategy

o

Decorator providing for dynamically pluggable wrappers.

Example To create a basic filter, you need to: 1. 2. 3. 4. 5. 6.

implement Filter interface implement doFilter method call doFilter from FilterChain object register the filter with the appropriate servlets and JSP pages Mapping the filter to specific pages disable the invoker servlet

General skeleton program import javax.servlet.*; import javax.servlet.http.*; public class MyFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse resonse, FilterChain chain) throws ServletException, IOException { //work on request and response }

chain.doFilter(request, response);

public void init(FilterConfig config) throws ServletException { //work on config } public void destroy() { //work on clean up } }

Register and filter mapping //in web.xml file <web-app> ... Before the servlet description MyFilter MyCoolFilter <description>This is my cool filter somePackage.MyFilter <param-name>yyy

<param-value>/xxx/zzz
MyFilter /xxx.jsp MyFilter <servlet-name>xxx ...

You may use filter mapping and servlet mapping in web.xml file to diable the invoker servlet to apply the filter.

Service Locator Definition Centralizing distributed service object lookups, providing a centralized point of control, acting as a cache that eliminates redundant lookups.

Where to use & benefits • • • • •

Lookup object in JNDI, RMI, JMS, etc. Encapsulate any vendor-specific features of lookup process Simplify the lookup process Improve the performance Related patterns include o Singlton combined with service locator to make sure only one lookup object exists.

Example Use a container as cache to hold the lookup object. One application only lookups same object once. Doing so will dramatically improve performance. Make sure the container used is thread-safe.

Transfer Object

Definition Using a serializable class to act as data carrier, grouping related attributes, forming a composite value and working as a return type from remote business method. Also known as Value object.

Where to use & benefits • • • • •

Get related values from remote business method. Fetch multiple value in one trip. Decrease network traffic. Minimize latency and server resource usage. Related patterns include o Composite view

Example In the J2EE server, the client tier may make several calls to retrieve data from the enterprise bean. Even in the same machine, the every call from the client tier to the server tier is a remote method call. Think about use Transfer Object design pattern to retrieve related attributes and return a single object instead of each call just for retrieving a single attribute value. The transfer object is passed by value to the client. All calls to the transfer object instance are local calls to the client, so such design saves a lot of network traffic. Let's say that you have a remote banking system. If the user has five requests one time, you should design your system to give response once, not five times. You may need to group all return values from these five requests to an object carrier and then return to client just once. Once the client program receives the instance of this object, it invokes the accessors and gets value to display. The total network traffic for one user just once.

Related Documents

Design Pattern
November 2019 18
Design Pattern
November 2019 26
Design Pattern
July 2020 5
Design Pattern
November 2019 17
Design Pattern 4 Asp
October 2019 10