public abstract class Address{ 2.. Builder This code example shows how to use the Builder pattern to create an appointment for the PIM.. The following list summarizes each class’s purpos
Trang 1Appendix A Full Code Examples
System Requirements
This appendix includes full, runnable code examples for each pattern Most of the patterns in the main part of this book included only the code that is crucial for your understanding of the pattern This appendix includes all required class files, and a RunPattern class, which shows you how the code runs, and includes print statements specifying what occurs in the code
The following patterns use Remote Method Invocation ( RMI ) in their code examples: Callback, HOPP, Router, Session, Successive Update, Transaction, and Worker Thread
To run these examples, your computer must be network-enabled Specifically, your system must be able to use TCP/IP sockets for networking and recognize " localhost " as a valid loopback IP address
The rmiregistry is started from the RunPattern file in each of these examples Because rmiregistry is a server process, these examples will appear to block when they are finished You must manually terminate the Java process to exit the rmiregistry
Trang 2Creational Pattern Code Examples
Abstract Factory
The following code samples show how international addresses and phone numbers can be supported in the Personal Information Manager with the Abstract Factory pattern The AddressFactory interface represents the factory itself:
Example A.1 AddressFactory.java
1 public interface AddressFactory{
2 public Address createAddress();
3 public PhoneNumber createPhoneNumber();
4 }
Note that the AddressFactory defines two factory methods, createAddress and createPhoneNumber The methods produce the abstract products Address and PhoneNumber, which define methods that these products support
Example A.2 Address.java
1 public abstract class Address{
2 private String street;
3 private String city;
4 private String region;
5 private String postalCode;
11 public String getStreet(){ return street; }
12 public String getCity(){ return city; }
13 public String getPostalCode(){ return postalCode; }
14 public String getRegion(){ return region; }
15 public abstract String getCountry();
16
17 public String getFullAddress(){
18 return street + EOL_STRING +
19 city + SPACE + postalCode + EOL_STRING;
20 }
21
22 public void setStreet(String newStreet){ street = newStreet; }
23 public void setCity(String newCity){ city = newCity; }
24 public void setRegion(String newRegion){ region = newRegion; }
25 public void setPostalCode(String newPostalCode){ postalCode = newPostalCode; }
26 }
Example A.3 PhoneNumber.java
1 public abstract class PhoneNumber{
2 private String phoneNumber;
3 public abstract String getCountryCode();
Trang 31 public class USAddressFactory implements AddressFactory{
2 public Address createAddress(){
3 return new USAddress();
4 }
5
6 public PhoneNumber createPhoneNumber(){
7 return new USPhoneNumber();
8 }
9 }
Example A.5 USAddress.java
1 public class USAddress extends Address{
2 private static final String COUNTRY = "UNITED STATES";
3 private static final String COMMA = ",";
4
5 public String getCountry(){ return COUNTRY; }
6
7 public String getFullAddress(){
8 return getStreet() + EOL_STRING +
9 getCity() + COMMA + SPACE + getRegion() +
10 SPACE + getPostalCode() + EOL_STRING +
11 COUNTRY + EOL_STRING;
12 }
13 }
Example A.6 USPhoneNumber.java
1 public class USPhoneNumber extends PhoneNumber{
2 private static final String COUNTRY_CODE = "01";
3 private static final int NUMBER_LENGTH = 10;
Example A.7 FrenchAddressFactory.java
1 public class FrenchAddressFactory implements AddressFactory{
2 public Address createAddress(){
3 return new FrenchAddress();
4 }
5
6 public PhoneNumber createPhoneNumber(){
7 return new FrenchPhoneNumber();
8 }
9 }
Example A.8 FrenchAddress.java
1 public class FrenchAddress extends Address{
2 private static final String COUNTRY = "FRANCE";
3
4 public String getCountry(){ return COUNTRY; }
5
6 public String getFullAddress(){
7 return getStreet() + EOL_STRING +
8 getPostalCode() + SPACE + getCity() +
9 EOL_STRING + COUNTRY + EOL_STRING;
10 }
11 }
Example A.9 FrenchPhoneNumber.java
1 public class FrenchPhoneNumber extends PhoneNumber{
2 private static final String COUNTRY_CODE = "33";
3 private static final int NUMBER_LENGTH = 9;
4
5 public String getCountryCode(){ return COUNTRY_CODE; }
Trang 4PhoneNumber interfaces There are no method calls which depend on the distinction between a USAddress and a
FrenchAddress
Example A.10 RunPattern.java
1 public class RunPattern{
2 public static void main(String [] arguments){
3 System.out.println("Example for the AbstractFactory pattern");
4 System.out.println();
5 System.out.println(" (take a look in the RunPattern code Notice that you can");
6 System.out.println(" use the Address and PhoneNumber classes when writing");
7 System.out.println(" almost all of the code This allows you to write a very");
8 System.out.println(" generic framework, and plug in Concrete Factories");
9 System.out.println(" and Products to specialize the behavior of your code)");
10 System.out.println();
11
12 System.out.println("Creating U.S Address and Phone Number:");
13 AddressFactory usAddressFactory = new USAddressFactory();
14 Address usAddress = usAddressFactory.createAddress();
15 PhoneNumber usPhone = usAddressFactory.createPhoneNumber();
30 System.out.println("Creating French Address and Phone Number:");
31 AddressFactory frenchAddressFactory = new FrenchAddressFactory();
32 Address frenchAddress = frenchAddressFactory.createAddress();
33 PhoneNumber frenchPhone = frenchAddressFactory.createPhoneNumber();
Trang 5Builder
This code example shows how to use the Builder pattern to create an appointment for the PIM The following list summarizes each class’s purpose:
AppointmentBuilder, MeetingBuilder – Builder classes
Scheduler – Director class
Appointment – Product
Address, Contact – Support classes, used to hold information relevant to the Appointment
InformationRequiredException – An Exception class produced when more data is required
For the base pattern, the AppointmentBuilder manages the creation of a complex product, which is an
Appointment in this example The AppointmentBuilder uses a series of build methods— buildAppointment,
buildLocation, buildDates, and buildAttendees — to create an Appointment and populate it
Example A.11 AppointmentBuilder.java
6 public static final int START_DATE_REQUIRED = 1;
7 public static final int END_DATE_REQUIRED = 2;
8 public static final int DESCRIPTION_REQUIRED = 4;
9 public static final int ATTENDEE_REQUIRED = 8;
10 public static final int LOCATION_REQUIRED = 16;
16 public void buildAppointment(){
17 appointment = new Appointment();
18 }
19
20 public void buildDates(Date startDate, Date endDate){
21 Date currentDate = new Date();
22 if ((startDate != null) && (startDate.after(currentDate))){
34 public void buildAttendees(ArrayList attendees){
35 if ((attendees != null) && (!attendees.isEmpty())){
Trang 63 public class Appointment{
4 private Date startDate;
5 private Date endDate;
6 private String description;
7 private ArrayList attendees = new ArrayList();
8 private Location location;
9 public static final String EOL_STRING =
10 System.getProperty("line.separator");
11
12 public Date getStartDate(){ return startDate; }
13 public Date getEndDate(){ return endDate; }
14 public String getDescription(){ return description; }
15 public ArrayList getAttendees(){ return attendees; }
16 public Location getLocation(){ return location; }
17
18 public void setDescription(String newDescription){ description = newDescription; }
19 public void setLocation(Location newLocation){ location = newLocation; }
20 public void setStartDate(Date newStartDate){ startDate = newStartDate; }
21 public void setEndDate(Date newEndDate){ endDate = newEndDate; }
22 public void setAttendees(ArrayList newAttendees){
38 public String toString(){
39 return " Description: " + description + EOL_STRING +
40 " Start Date: " + startDate + EOL_STRING +
41 " End Date: " + endDate + EOL_STRING +
42 " Location: " + location + EOL_STRING +
3 public class Scheduler{
4 public Appointment createAppointment(AppointmentBuilder builder,
5 Date startDate, Date endDate, String description,
6 Location location, ArrayList attendees) throws InformationRequiredException {
7 if (builder == null){
Trang 7The responsibilities of each class are summarized here:
Scheduler – Calls the appropriate build methods on AppointmentBuilder; returns a complete Appointment
object to its caller
AppointmentBuilder – Contains build methods and enforces business rules; creates the actual Appointment
object
Appointment – Holds information about an appointment
The MeetingBuilder class in Example A.14 demonstrates one of the benefits of using the Builder pattern To add additional rules for the Appointment, extend the existing builder In this case, the MeetingBuilder enforces an additional constraint: for an Appointment that is a meeting, both start and end dates must be specified
Example A.14 MeetingBuilder.java
1 import java.util.Date;
2 import java.util.Vector;
3
4 public class MeetingBuilder extends AppointmentBuilder{
5 public Appointment getAppointment() throws InformationRequiredException{
Support classes used for this example include the class InformationRequiredException and the interfaces
Location and Contact The Address and Contact interfaces are marker interfaces used to represent supporting information for the Appointment in this example; their implementation is represented by the LocationImpl and
ContactImpl classes
Example A.15 InformationRequiredException.java
1 public class InformationRequiredException extends Exception{
2 private static final String MESSAGE = "Appointment cannot be created because further
information is required";
3 public static final int START_DATE_REQUIRED = 1;
4 public static final int END_DATE_REQUIRED = 2;
5 public static final int DESCRIPTION_REQUIRED = 4;
6 public static final int ATTENDEE_REQUIRED = 8;
7 public static final int LOCATION_REQUIRED = 16;
8 private int informationRequired;
Trang 81 import java.io.Serializable;
2 public interface Location extends Serializable {
3 public String getLocation();
4 public void setLocation(String newLocation);
5 }
Example A.17 LocationImpl.java
1 public class LocationImpl implements Location{
2 private String location;
2 public interface Contact extends Serializable{
3 public static final String SPACE = " ";
4 public String getFirstName();
5 public String getLastName();
6 public String getTitle();
7 public String getOrganization();
8
9 public void setFirstName(String newFirstName);
10 public void setLastName(String newLastName);
11 public void setTitle(String newTitle);
12 public void setOrganization(String newOrganization);
13 }
Example A.19 ContactImpl.java
1 public class ContactImpl implements Contact{
2 private String firstName;
3 private String lastName;
4 private String title;
5 private String organization;
6
7 public ContactImpl(String newFirstName, String newLastName,
8 String newTitle, String newOrganization){
15 public String getFirstName(){ return firstName; }
16 public String getLastName(){ return lastName; }
17 public String getTitle(){ return title; }
18 public String getOrganization(){ return organization; }
19
20 public void setFirstName(String newFirstName){ firstName = newFirstName; }
21 public void setLastName(String newLastName){ lastName = newLastName; }
22 public void setTitle(String newTitle){ title = newTitle; }
23 public void setOrganization(String newOrganization){ organization = newOrganization; }
24
25 public String toString(){
26 return firstName + SPACE + lastName;
27 }
28 }
The RunPattern file executes this example It demonstrates the use of the Builder pattern by creating three
separate Appointment objects using the AppointmentBuilder and MeetingBuilder
Example A.20 RunPattern.java
1 import java.util.Calendar;
2 import java.util.Date;
3 import java.util.ArrayList;
Trang 94 public class RunPattern{
5 private static Calendar dateCreator = Calendar.getInstance();
6
7 public static void main(String [] arguments){
8 Appointment appt = null;
9
10 System.out.println("Example for the Builder pattern");
11 System.out.println();
12 System.out.println("This example demonstrates the use of the Builder");
13 System.out.println("pattern to create Appointment objects for the PIM.");
14 System.out.println();
15
16 System.out.println("Creating a Scheduler for the example.");
17 Scheduler pimScheduler = new Scheduler();
37 System.out.println("Creating a MeetingBuilder for the example.");
38 MeetingBuilder mtgBuilder = new MeetingBuilder();
39 try{
40 System.out.println("Creating a new Appointment with a MeetingBuilder");
41 System.out.println("(notice that the same create arguments will produce");
42 System.out.println(" an exception, since the MeetingBuilder enforces a");
43 System.out.println(" mandatory end date)");
57 System.out.println("Creating a new Appointment with a MeetingBuilder");
58 System.out.println("(This time, the MeetingBuilder will provide an end date)");
77 public static Date createDate(int year, int month, int day, int hour, int minute){
78 dateCreator.set(year, month, day, hour, minute);
79 return dateCreator.getTime();
80 }
81
Trang 1082 public static ArrayList createAttendees(int numberToCreate){
83 ArrayList group = new ArrayList();
84 for (int i = 0; i < numberToCreate; i++){
85 group.add(new ContactImpl("John", getLastName(i), "Employee (nonexempt)", "Yoyodyne
109 public static void printExceptions(InformationRequiredException exc){
110 int statusCode = exc.getInformationRequired();
111
112 System.out.println("Unable to create Appointment: additional information is
required");
113 if ((statusCode & InformationRequiredException.START_DATE_REQUIRED) > 0){
114 System.out.println(" A start date is required for this appointment to be
complete.");
115 }
116 if ((statusCode & InformationRequiredException.END_DATE_REQUIRED) > 0){
117 System.out.println(" An end date is required for this appointment to be
complete.");
118 }
119 if ((statusCode & InformationRequiredException.DESCRIPTION_REQUIRED) > 0){
120 System.out.println(" A description is required for this appointment to be
complete.");
121 }
122 if ((statusCode & InformationRequiredException.ATTENDEE_REQUIRED) > 0){
123 System.out.println(" At least one attendee is required for this appointment to
be complete.");
124 }
125 if ((statusCode & InformationRequiredException.LOCATION_REQUIRED) > 0){
126 System.out.println(" A location is required for this appointment to be
Trang 11Factory Method
The following example uses the Factory Method pattern to produce an editor for the PIM The PIM tracks a lot of information, and there are many cases where users need an editor to create or modify data The example uses interfaces to improve the overall flexibility of the system
The Editable interface defines a builder method, getEditor, which returns an ItemEditor interface The benefit is that any item can provide an editor for itself, producing an object that knows what parts of a business object can change and how they can be changed The only thing the user interface needs to do is use the
Editable interface to get an editor
Example A.21 Editable.java
1 public interface Editable {
2 public ItemEditor getEditor();
3 }
The ItemEditor interface provides two methods: getGUI and commitChanges The getGUI method is another Factory Method—it returns a JComponent that provides a Swing GUI to edit the current item This makes a very flexible system; to add a new type of item, the user interface can remain the same, because it only uses the
Editable and the ItemEditor interfaces
The JComponent returned by getGUI can have anything in it required to edit the item in the PIM The user
interface can simply the acquired JComponent in its editor window and use the JComponent functionality to edit the item Since not everything in an application needs to be graphical, it could also be a good idea to include a
getUI method that would return an Object or some other nongraphical interface
The second method, commitChanges, allows the UI to tell the editor that the user wants to finalize the changes he or she has made
Example A.22 ItemEditor.java
1 import javax.swing.JComponent;
2 public interface ItemEditor {
3 public JComponent getGUI();
4 public void commitChanges();
5 }
The following code shows the implementation for one of the PIM items, Contact The Contact class defines two attributes: the name of the person and their relationship with the user These attributes provide a sample of some
of the information, which could be included in an entry in the PIM
Example A.23 Contact.java
8 public class Contact implements Editable, Serializable {
9 private String name;
10 private String relationship;
11
12 public ItemEditor getEditor() {
13 return new ContactEditor();
14 }
15
16 private class ContactEditor implements ItemEditor, Serializable {
17 private transient JPanel panel;
18 private transient JTextField nameField;
19 private transient JTextField relationField;
20
21 public JComponent getGUI() {
22 if (panel == null) {
23 panel = new JPanel();
24 nameField = new JTextField(name);
25 relationField = new JTextField(relationship);
26 panel.setLayout(new GridLayout(2,2));
27 panel.add(new JLabel("Name:"));
Trang 12Contact implements the Editable interface, and provides its own editor That editor only applies to the Contact
class, and needs to change certain attributes of the Contact, it is best to use an inner class The inner class has direct access to the attributes of the outer class If you used another (non-inner) class, Contact would need to provide accessor and mutator methods, making it harder to restrict access to the object’s private data
Note that the editor itself is not a Swing component, but only an object that can serve as a factory for such a component The greatest benefit is that you can serialize and send this object across a stream To implement this feature, declare all Swing component attributes in ContactEditor transient—they’re constructed when and where they’re needed
The EditorGui represents a generic editor you might use in the PIM Note that the class uses the ItemEditor
interface to entirely manage its edit window It constructs a JPanel for its edit window, and places the
JComponent obtained by the call to getGUI inside The Swing component provides all the edit capabilities for the
Contact, while the EditorGui provides control buttons and a JTextArea to display the state of the Contact
12 public class EditorGui implements ActionListener{
13 private JFrame mainFrame;
14 private JTextArea display;
15 private JButton update, exit;
16 private JPanel controlPanel, displayPanel, editorPanel;
17 private ItemEditor editor;
23 public void createGui(){
24 mainFrame = new JFrame("Factory Pattern Example");
25 Container content = mainFrame.getContentPane();
26 content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
Trang 1332 displayPanel = new JPanel();
33 display = new JTextArea(10, 40);
34 display.setEditable(false);
35 displayPanel.add(display);
36 content.add(displayPanel);
37
38 controlPanel = new JPanel();
39 update = new JButton("Update Item");
40 exit = new JButton("Exit");
54 public void actionPerformed(ActionEvent evt){
55 Object originator = evt.getSource();
64 private class WindowCloseManager extends WindowAdapter{
65 public void windowClosing(WindowEvent evt){
Note that the Update Item button makes a call to the ItemEditor 's commitChanges method
The RunPattern class runs this pattern by creating a Contact and an EditorGui object The EditorGui
constructor sets the ItemEditor for the example
Example A.25 RunPattern.java
7 public class RunPattern{
8 public static void main(String [] arguments){
9 System.out.println("Example for the FactoryMethod pattern");
19 System.out.println("It accepts an argument of type ItemEditor, and delegates");
20 System.out.println(" all editing tasks to its ItemEditor and the associated GUI.");
Trang 1421 System.out.println(" The getEditor() Factory Method is used to obtain the
ItemEditor");
22 System.out.println(" for the example.");
23 System.out.println();
24 System.out.println("Notice that the editor in the top portion of the GUI is,");
25 System.out.println(" in fact, returned by the ItemEditor belonging to the");
26 System.out.println(" Contact class, and has appropriate fields for that class.");
Trang 15Prototype
The Address class in this example uses the Prototype pattern to create an address based on an existing entry The core functionality for the pattern is defined in the interface Copyable
Example A.26 Copyable.java
1 public interface Copyable{
2 public Object copy();
3 }
The Copyable interface defines a copy method and guarantees that any classes that implement the interface will define a copy operation This example produces a shallow copy—that is, it copies the object references from the original address to the duplicate
The code also demonstrates an important feature of the copy operation: not all fields must necessarily be
duplicated In this case, the address type is not copied to the new object A user would manually specify a new address type from the PIM user interface
Example A.27 Address.java
1 public class Address implements Copyable{
2 private String type;
3 private String street;
4 private String city;
5 private String state;
6 private String zipCode;
7 public static final String EOL_STRING =
8 System.getProperty("line.separator");
9 public static final String COMMA = ",";
10 public static final String HOME = "home";
11 public static final String WORK = "work";
12
13 public Address(String initType, String initStreet,
14 String initCity, String initState, String initZip){
22 public Address(String initStreet, String initCity,
23 String initState, String initZip){
24 this(WORK, initStreet, initCity, initState, initZip);
31 public String getType(){ return type; }
32 public String getStreet(){ return street; }
33 public String getCity(){ return city; }
34 public String getState(){ return state; }
35 public String getZipCode(){ return zipCode; }
36
37 public void setType(String newType){ type = newType; }
38 public void setStreet(String newStreet){ street = newStreet; }
39 public void setCity(String newCity){ city = newCity; }
40 public void setState(String newState){ state = newState; }
41 public void setZipCode(String newZip){ zipCode = newZip; }
42
43 public Object copy(){
44 return new Address(street, city, state, zipCode);
45 }
46
47 public String toString(){
48 return "\t" + street + COMMA + " " + EOL_STRING +
49 "\t" + city + COMMA + " " + state + " " + zipCode;
50 }
51 }
Trang 16The RunPattern class demonstrates the use of this pattern by creating an Address object, then duplicating that
object by calling its copy method The fact that the Address objects return two different hash code values
(numeric values that represent unique object identity) further confirms that the copy operation has produced a
different object from the first
Example A.28 RunPattern.java
1 public class RunPattern{
2 public static void main(String [] arguments){
3 System.out.println("Example for Prototype pattern");
4 System.out.println();
5 System.out.println("This example will create an Address object,");
6 System.out.println(" which it will then duplicate by calling the");
7 System.out.println(" object's clone method.");
8 System.out.println();
9
10 System.out.println("Creating first address.");
11 Address address1 = new Address("8445 Silverado Trail", "Rutherford", "CA", "91734");
12 System.out.println("First address created.");
13 System.out.println(" Hash code = " + address1.hashCode());
14 System.out.println(address1);
15 System.out.println();
16
17 System.out.println("Creating second address using the clone() method.");
18 Address address2 = (Address)address1.copy();
19 System.out.println("Second address created.");
20 System.out.println(" Hash code = " + address2.hashCode());
Trang 17Singleton
Application users want the option of undoing previous commands To support that functionality, a history list is needed That history list has to be accessible from everywhere in the PIM and only one instance of it is needed Therefore, it’s a perfect candidate for the implementation of the Singleton pattern
Example A.29 HistoryList.java
1 import java.util.ArrayList;
2 import java.util.Collections;
3 import java.util.List;
4 public class HistoryList{
5 private List history = Collections.synchronizedList(new ArrayList());
6 private static HistoryList instance = new HistoryList();
22 public String toString(){
23 StringBuffer result = new StringBuffer();
24 for (int i = 0; i < history.size(); i++){
Example A.30 SingletonGUI.java
11 public class SingletonGui implements ActionListener{
12 private JFrame mainFrame;
13 private JTextArea display;
14 private JButton newContact, newAppointment, undo, refresh, exit;
15 private JPanel controlPanel, displayPanel;
16 private static int historyCount;
17
18 public void createGui(){
19 mainFrame = new JFrame("Singleton Pattern Example");
Trang 1820 Container content = mainFrame.getContentPane();
21 content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
22
23 displayPanel = new JPanel();
24 display = new JTextArea(20, 60);
25 display.setEditable(false);
26 displayPanel.add(display);
27 content.add(displayPanel);
28
29 controlPanel = new JPanel();
30 newContact = new JButton("Create contact");
31 newAppointment = new JButton("Create appointment");
32 undo = new JButton("Undo");
33 refresh = new JButton("Refresh");
34 exit = new JButton("Exit");
53 public void refreshDisplay(String actionMessage){
54 display.setText(actionMessage + "\nCOMMAND HISTORY:\n" +
55 HistoryList.getInstance().toString());
56 }
57
58 public void actionPerformed(ActionEvent evt){
59 Object originator = evt.getSource();
60 if (originator == newContact){
61 addCommand(" New Contact");
62 }
63 else if (originator == newAppointment){
64 addCommand(" New Appointment");
77 private class WindowCloseManager extends WindowAdapter{
78 public void windowClosing(WindowEvent evt){
88 private void undoCommand(){
89 Object result = HistoryList.getInstance().undoCommand();