Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
202
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

3.public class SupportedProjectItem extends ProjectDecorator{

4.private ArrayList supportingDocuments = new ArrayList();

6.public SupportedProjectItem(){ }

7.public SupportedProjectItem(File newSupportingDocument){

8.addSupportingDocument(newSupportingDocument);

9.}

10.

11.public ArrayList getSupportingDocuments(){

12.return supportingDocuments;

13.}

14.

15.public void addSupportingDocument(File document){

16.if (!supportingDocuments.contains(document)){

17. supportingDocuments.add(document);

18.}

19.}

21.public void removeSupportingDocument(File document){

22.supportingDocuments.remove(document);

23.}

24.

25.public String toString(){

26.return getProjectItem().toString() + EOL_STRING

27. + "\tSupporting Documents: " + supportingDocuments;

28.}

29.}

The benefit of defining additional capabilities in this way is that it is easy to create project items that have a combination of capabilities. Using these classes, you can make a simple task that depends on another project item, or a task with supporting documents. You can even chain Decorators together and create a task that depends on another task and has supporting documents. This flexibility is a key strength of the Decorator pattern.

In this example, the Contact interface and its implementer ContactImpl provide support for an owner of a Task

or Deliverable.

Example A.160 Contact.java

1.import java.io.Serializable;

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.161 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(){}

8.public ContactImpl(String newFirstName, String newLastName,

9.String newTitle, String newOrganization){

10. firstName = newFirstName;

11. lastName = newLastName;

12. title = newTitle;

13. organization = newOrganization;

14. }

15.

16.public String getFirstName(){ return firstName; }

17.public String getLastName(){ return lastName; }

18.public String getTitle(){ return title; }

19.public String getOrganization(){ return organization; }

21.public void setFirstName(String newFirstName){ firstName = newFirstName; }

22.public void setLastName(String newLastName){ lastName = newLastName; }

23.public void setTitle(String newTitle){ title = newTitle; }

304

24. public void setOrganization(String newOrganization){ organization = newOrganization; }

25.

26.public String toString(){

27.return firstName + SPACE + lastName;

28.}

29.}

The RunPattern class creates several ProjectItems and prints out their String values. Next, it creates several Decorators, associates them with one of the Task objects by calling the setProjectItem methods, and shows the String value of the newly decorated Task.

Example A.162 RunPattern.java

1.import java.io.File;

2.public class RunPattern{

3.public static void main(String [] arguments){

4.System.out.println("Example for the Decorator pattern");

5.System.out.println();

6.System.out.println("This demonstration will show how Decorator classes can be

used");

7.System.out.println(" to extend the basic functionality of ProjectItems. The Task

and");

8.System.out.println(" Deliverable classes provide the basic ProjectItems, and

their");

9.System.out.println(" functionality will be extended by adding subclasses of the");

10.System.out.println(" abstract class ProjectDecorator.");

11.System.out.println();

12.System.out.println("Note that the toString method has been overridden for all

ProjectItems,");

13 System.out.println(" to more effectively show how Decorators are associated with their");

14.System.out.println(" ProjectItems.");

15.System.out.println();

16.

17.System.out.println("Creating ProjectItems.");

18.Contact contact1 = new ContactImpl("Simone", "Roberto", "Head Researcher and Chief

Archivist", "Institute for Advanced (Java) Studies");

19.Task task1 = new Task("Perform months of diligent research", contact1, 20.0);

20.Task task2 = new Task("Obtain grant from World Java Foundation", contact1, 40.0);

21.Deliverable deliverable1 = new Deliverable("Java History", "Comprehensive history

of the design of all Java APIs", contact1);

22.System.out.println("ProjectItem objects created. Results:");

23.System.out.println(task1);

24.System.out.println(task2);

25.System.out.println(deliverable1);

26.System.out.println();

27.

28.System.out.println("Creating decorators");

29.ProjectDecorator decorator1 = new SupportedProjectItem(new File(" JavaHistory.txt"));

30.ProjectDecorator decorator2 = new DependentProjectItem(task2);

31.System.out.println("Decorators created. Adding decorators to the first task");

32.decorator1.setProjectItem(task1);

33.decorator2.setProjectItem(decorator1);

34.System.out.println();

35.System.out.println("Decorators added. Results");

36.System.out.println(decorator2);

37.

38.System.out.println("");

39.}

40.}

305

Facade

To make the PIM more functional for users, you want to give them the opportunity to customize the application. Some examples of items to customize include font type, font size, colors, which services to start when, default currency, etc. This example tracks a set of nationality-based settings.

In this example, the Facade class is the InternationalizationWizard. This class coordinates between a client and a number of objects associated with a selected nationality.

Example A.163 InternationalizationWizard.java

1.import java.util.HashMap;

2.import java.text.NumberFormat;

3.import java.util.Locale;

4.public class InternationalizationWizard{

5.private HashMap map;

6.private Currency currency = new Currency();

7.private InternationalizedText propertyFile = new InternationalizedText();

9.public InternationalizationWizard() {

10.map = new HashMap();

11.Nation[] nations = {

12. new Nation("US", '$', "+1", "us.properties", NumberFormat. getInstance(Locale.US)), 13. new Nation("The Netherlands", 'f', "+31", "dutch.properties",

NumberFormat.getInstance(Locale.GERMANY)),

14.new Nation("France", 'f', "+33", "french.properties", NumberFormat.

getInstance(Locale.FRANCE))

15.};

16.for (int i = 0; i < nations.length; i++) {

17. map.put(nations[i].getName(), nations[i]);

18.}

19.}

21.public void setNation(String name) {

22.Nation nation = (Nation)map.get(name);

23.if (nation != null) {

24.

currency.setCurrencySymbol(nation.getSymbol());

25.

currency.setNumberFormat(nation.getNumberFormat());

26.

PhoneNumber.setSelectedInterPrefix(nation.getDialingPrefix());

27.

propertyFile.setFileName(nation.getPropertyFileName());

28.}

29.}

31.public Object[] getNations(){

32.return map.values().toArray();

33.}

34.public Nation getNation(String name){

35.return (Nation)map.get(name);

36.}

37.public char getCurrencySymbol(){

38.return currency.getCurrencySymbol();

39.}

40.public NumberFormat getNumberFormat(){

41.return currency.getNumberFormat();

42.}

43.public String getPhonePrefix(){

44.return PhoneNumber.getSelectedInterPrefix();

45.}

46.public String getProperty(String key){

47.return propertyFile.getProperty(key);

48.}

49.public String getProperty(String key, String defaultValue){

50.return propertyFile.getProperty(key, defaultValue);

51.}

52.}

Note that the InternationalizationWizard has a number of get methods, which it delegates to its associated objects. It also has a method setNation, used to change the nation used by the client.

Although the Facade manages the internationalized settings for a number of objects in this example, it is still possible to manage each object individually. This is one of the benefits of this pattern—it allows a group of objects to be managed collectively in some situations, but still provides the freedom to individually manage the components as well.

306

Calling the setNation method in this class sets the current nation. That makes the wizard alter the Currency setting, the PhoneNumber, and a set of localized language strings, InternationalizedText.

Example A.164 Currency.java

1.import java.text.NumberFormat;

2.public class Currency{

3.private char currencySymbol;

4.private NumberFormat numberFormat;

6.public void setCurrencySymbol(char newCurrencySymbol){ currencySymbol =

newCurrencySymbol; }

7.public void setNumberFormat(NumberFormat newNumberFormat){ numberFormat =

newNumberFormat; }

8.

9.public char getCurrencySymbol(){ return currencySymbol; }

10.public NumberFormat getNumberFormat(){ return numberFormat; }

11.}

Example A.165 InternationalizedText.java

1.import java.util.Properties;

2.import java.io.File;

3.import java.io.IOException;

4.import java.io.FileInputStream;

5.public class InternationalizedText{

6.private static final String DEFAULT_FILE_NAME = "";

7.private Properties textProperties = new Properties();

9.public InternationalizedText(){

10.this(DEFAULT_FILE_NAME);

11.}

12.public InternationalizedText(String fileName){

13.loadProperties(fileName);

14.}

15.

16.public void setFileName(String newFileName){

17.if (newFileName != null){

18. loadProperties(newFileName);

19.}

20.}

21.public String getProperty(String key){

22.return getProperty(key, "");

23.}

24.public String getProperty(String key, String defaultValue){

25.return textProperties.getProperty(key, defaultValue);

26.}

27.

28.private void loadProperties(String fileName){

29.try{

30. FileInputStream input = new FileInputStream(fileName);

31. textProperties.load(input);

32.}

33.catch (IOException exc){

34. textProperties = new Properties();

35.}

36.}

37.}

Example A.166 PhoneNumber.java

1.public class PhoneNumber {

2.private static String selectedInterPrefix;

3.private String internationalPrefix;

4.private String areaNumber;

5.private String netNumber;

6.

7.public PhoneNumber(String intPrefix, String areaNumber, String netNumber) {

8.this.internationalPrefix = intPrefix;

9.this.areaNumber = areaNumber;

10.this.netNumber = netNumber;

11.}

12.

13.public String getInternationalPrefix(){ return internationalPrefix; }

14.public String getAreaNumber(){ return areaNumber; }

15.public String getNetNumber(){ return netNumber; }

16.public static String getSelectedInterPrefix(){ return selectedInterPrefix; }

307