设计模式教程(Design Patterns Tutorial)笔记之二 结构型模式(Structural Patterns)

目录

· Decorator

    · What is the Decorator Design Pattern?

    · Sample Code 

· Adapter

    · What is the Adapter Design Pattern?

    · Sample Code

· Facade

    · What is the Facade Design Pattern?

    · Sample Code

· Bridge

    · What is the Bridge Design Pattern?

    · When to use the Bridge Design Pattern?

    · Sample Code

· Flyweight

    · What is the Flyweight Design Pattern?

    · Sample Code

· Proxy

    · What is the Proxy Design Pattern?

    · Sample Code


Decorator

What is the Decorator Design Pattern?

• The Decorator allows you to modify an object dynamically.

• You would use it when you want the capabilities of inheritance with subclasses, but you need to add functionality at run time.

• It is more flexible than inheritance.

• Simplifies code because you add functionality using many simple classes.

• Rather than rewrite old code you can extend with new code.

Sample Code 

• Pizza.java 

 1 // Blueprint for classes that will have decorators
 2 
 3 public interface Pizza {
 4     
 5     public String getDescription();
 6     
 7     public double getCost();
 8     
 9 }
10 
11 
12 /* 
13 public abstract class Pizza{
14 
15     
16     public abstract void setDescription(String newDescription);
17     public abstract String getDescription();
18     
19     public abstract void setCost(double newCost);
20     public abstract double getCost();
21     
22     // I could use getter and setter methods for every 
23     // potential Pizza topping
24     
25 }
26 */

 • ThreeCheesePizza.java

 1 // By going this route I'll have to create a new subclass
 2 // for an infinite number of pizza.
 3 // I'd also have to change prices in many classes 
 4 // when just 1 Pizza topping cost changes
 5 
 6 // Inheritance is static while composition is dynamic
 7 // Through composition I'll be able to add new functionality
 8 // by writing new code rather than by changing current code
 9 
10 public class ThreeCheesePizza extends Pizza{
11 
12     private String description = "Mozzarella, Fontina, Parmesan Cheese Pizza";
13     private double cost = 10.50;
14     
15     public void setDescription(String newDescription) {
16         
17         description = newDescription;
18         
19     }
20 
21     public String getDescription() {
22     
23         return description;
24         
25     }
26 
27     public void setCost(double newCost) {
28         
29         cost = newCost;
30         
31     }
32 
33     public double getCost() {
34         
35         return cost;
36         
37     }
38 }

 • PlainPizza.java

 1 // Implements the Pizza interface with only the required
 2 // methods from the interface
 3 
 4 // Every Pizza made will start as a PlainPizza
 5 
 6 public class PlainPizza implements Pizza {
 7  
 8     public String getDescription() {
 9         
10         return "Thin dough";
11     
12     }
13 
14     public double getCost() {
15 
16         System.out.println("Cost of Dough: " + 4.00);
17         
18         return 4.00;
19     
20     }
21  
22 }

 • ToppingDecorator.java

 1 // Has a "Has a" relationship with Pizza. This is an
 2 // Aggregation Relationship
 3 
 4 abstract class ToppingDecorator implements Pizza {
 5 
 6     protected Pizza tempPizza;
 7     
 8     // Assigns the type instance to this attribute
 9     // of a Pizza
10     
11     // All decorators can dynamically customize the Pizza
12     // instance PlainPizza because of this
13     
14     public ToppingDecorator(Pizza newPizza){
15         
16         tempPizza = newPizza;
17         
18     }
19     
20     public String getDescription() {
21         
22         return tempPizza.getDescription();
23         
24     }
25 
26     public double getCost() {
27         
28         return tempPizza.getCost();
29         
30     }
31     
32 }

 • Mozzarella.java

 1 public class Mozzarella extends ToppingDecorator {
 2 
 3     public Mozzarella(Pizza newPizza) {
 4         
 5         super(newPizza);
 6         
 7         System.out.println("Adding Dough");
 8         
 9         System.out.println("Adding Moz");
10     }
11     
12     // Returns the result of calling getDescription() for
13     // PlainPizza and adds " mozzarella" to it
14     
15     public String getDescription(){
16         
17         return tempPizza.getDescription() + ", mozzarella";
18         
19     }
20     
21     public double getCost(){
22         
23         System.out.println("Cost of Moz: " + .50);
24         
25         return tempPizza.getCost() + .50;
26         
27     }
28     
29 }

 • TomatoSauce.java

 1 public class TomatoSauce extends ToppingDecorator {
 2 
 3     public TomatoSauce(Pizza newPizza) {
 4         super(newPizza);
 5         
 6         System.out.println("Adding Sauce");
 7     }
 8     
 9     // Returns the result of calling getDescription() for
10     // PlainPizza, Mozzarella and then TomatoSauce
11     
12     public String getDescription(){
13         
14         return tempPizza.getDescription() + ", tomato sauce";
15         
16     }
17     
18     public double getCost(){
19         
20         System.out.println("Cost of Sauce: " + .35);
21         
22         return tempPizza.getCost() + .35;
23         
24     }
25     
26 }

 • PizzaMaker.java

 1 public class PizzaMaker {
 2     
 3     public static void main(String[] args){
 4         
 5         // The PlainPizza object is sent to the Mozzarella constructor
 6         // and then to the TomatoSauce constructor
 7         
 8         Pizza basicPizza = new TomatoSauce(new Mozzarella(new PlainPizza()));
 9         
10         System.out.println("Ingredients: " + basicPizza.getDescription());
11         
12         System.out.println("Price: " + basicPizza.getCost());
13         
14     }
15     
16 }

Adapter

What is the Adapter Design Pattern?

• Allows 2 incompatible interfaces to work together.

• Used when the client expects a (target) interface.

• The Adapter class allows the use of the available interface and the Target interface.

• Any class can work together as long as the Adapter solves the issue that all classes must implement every method defined by the shared interface.

Sample Code

• EnemyAttacker.java

 1 // This is the Target Interface : This is what the client
 2 // expects to work with. It is the adapters job to make new 
 3 // classes compatible with this one.
 4 
 5 public interface EnemyAttacker {
 6     
 7     public void fireWeapon();
 8     
 9     public void driveForward();
10     
11     public void assignDriver(String driverName);
12     
13 }

• EnemyTank.java

 1 // EnemyTank implements EnemyAttacker perfectly
 2 // Our job is to make classes with different methods
 3 // from EnemyAttacker to work with the EnemyAttacker interface
 4 
 5 import java.util.Random;
 6 
 7 public class EnemyTank implements EnemyAttacker{
 8     
 9     Random generator = new Random();
10 
11     public void fireWeapon() {
12         
13         int attackDamage = generator.nextInt(10) + 1;
14         
15         System.out.println("Enemy Tank Does " + attackDamage + " Damage");
16         
17     }
18 
19     public void driveForward() {
20         
21         int movement = generator.nextInt(5) + 1;
22         
23         System.out.println("Enemy Tank moves " + movement + " spaces");
24         
25     }
26 
27     public void assignDriver(String driverName) {
28         
29         System.out.println(driverName + " is driving the tank");
30         
31     }
32     
33 }

• EnemyRobot.java

 1 // This is the Adaptee. The Adapter sends method calls
 2 // to objects that use the EnemyAttacker interface
 3 // to the right methods defined in EnemyRobot
 4 
 5 import java.util.Random;
 6 
 7 public class EnemyRobot{
 8 
 9     Random generator = new Random();
10     
11     public void smashWithHands() {
12         
13         int attackDamage = generator.nextInt(10) + 1;
14         
15         System.out.println("Enemy Robot Causes " + attackDamage + " Damage With Its Hands");
16         
17     }
18 
19     public void walkForward() {
20         
21         int movement = generator.nextInt(5) + 1;
22         
23         System.out.println("Enemy Robot Walks Forward " + movement + " spaces");
24         
25     }
26 
27     public void reactToHuman(String driverName) {
28         
29         System.out.println("Enemy Robot Tramps on " + driverName);
30         
31     }
32     
33     
34     
35 }

• EnemyRobotAdapter.java

 1 // The Adapter must provide an alternative action for 
 2 // the the methods that need to be used because
 3 // EnemyAttacker was implemented.
 4 
 5 // This adapter does this by containing an object
 6 // of the same type as the Adaptee (EnemyRobot)
 7 // All calls to EnemyAttacker methods are sent
 8 // instead to methods used by EnemyRobot
 9 
10 public class EnemyRobotAdapter implements EnemyAttacker{
11 
12     EnemyRobot theRobot;
13     
14     public EnemyRobotAdapter(EnemyRobot newRobot){
15         
16         theRobot = newRobot;
17         
18     }
19     
20     public void fireWeapon() {
21         
22         theRobot.smashWithHands();
23         
24     }
25 
26     public void driveForward() {
27         
28         theRobot.walkForward();
29         
30     }
31 
32     public void assignDriver(String driverName) {
33         
34         theRobot.reactToHuman(driverName);
35         
36     }
37     
38     
39     
40 }

• TestEnemyAttackers.java

 1 public class TestEnemyAttackers{
 2     
 3     public static void main(String[] args){
 4         
 5         EnemyTank rx7Tank = new EnemyTank();
 6         
 7         EnemyRobot fredTheRobot = new EnemyRobot();
 8         
 9         EnemyAttacker robotAdapter = new EnemyRobotAdapter(fredTheRobot);
10         
11         System.out.println("The Robot");
12         
13         fredTheRobot.reactToHuman("Paul");
14         fredTheRobot.walkForward();
15         fredTheRobot.smashWithHands();
16         System.out.println();
17         
18         System.out.println("The Enemy Tank");
19         
20         rx7Tank.assignDriver("Frank");
21         rx7Tank.driveForward();
22         rx7Tank.fireWeapon();
23         System.out.println();
24         
25         System.out.println("The Robot with Adapter");
26         
27         robotAdapter.assignDriver("Mark");
28         robotAdapter.driveForward();
29         robotAdapter.fireWeapon();
30 
31     }
32     
33 }

Facade

What is the Facade Design Pattern?

• When you create a simplified interface that performs many other actions behind the scenes.

• Can I withdrawal $50 from the bank?

• Check if the checking account is valid.

• Check if the security code is valid.

• Check if funds are available.

• Make changes accordingly.

Sample Code

• WelcomeToBank.java

 1 public class WelcomeToBank{
 2     
 3     public WelcomeToBank() {
 4         
 5         System.out.println("Welcome to ABC Bank");
 6         System.out.println("We are happy to give you your money if we can find it
");
 7         
 8         
 9     }
10     
11 }

• AccountNumberCheck.java

 1 public class AccountNumberCheck{
 2     
 3     private int accountNumber = 12345678;
 4     
 5     public int getAccountNumber() { return accountNumber; }
 6     
 7     public boolean accountActive(int acctNumToCheck){
 8         
 9         if(acctNumToCheck == getAccountNumber()) {
10             
11             return true;
12             
13         } else {
14             
15             return false;
16             
17         }
18         
19     }
20     
21 }

• SecurityCodeCheck.java

 1 public class SecurityCodeCheck {
 2     
 3     private int securityCode = 1234;
 4     
 5     public int getSecurityCode() { return securityCode; }
 6     
 7     public boolean isCodeCorrect(int secCodeToCheck){
 8         
 9         if(secCodeToCheck == getSecurityCode()) {
10             
11             return true;
12             
13         } else {
14             
15             return false;
16             
17         }
18         
19     }
20     
21 }

• FundsCheck.java

 1 public class FundsCheck {
 2     
 3     private double cashInAccount = 1000.00;
 4     
 5     public double getCashInAccount() { return cashInAccount; }
 6     
 7     public void decreaseCashInAccount(double cashWithdrawn) { cashInAccount -= cashWithdrawn; }
 8     
 9     public void increaseCashInAccount(double cashDeposited) { cashInAccount += cashDeposited; }
10     
11     public boolean haveEnoughMoney(double cashToWithdrawal) {
12         
13         if(cashToWithdrawal > getCashInAccount()) {
14             
15             System.out.println("Error: You don't have enough money");
16             System.out.println("Current Balance: " + getCashInAccount());
17             
18             return false;
19             
20         } else {
21             
22             decreaseCashInAccount(cashToWithdrawal);
23             
24             System.out.println("Withdrawal Complete: Current Balance is " + getCashInAccount());
25             
26             return true;
27             
28         }
29         
30     }
31     
32     public void makeDeposit(double cashToDeposit) {
33         
34         increaseCashInAccount(cashToDeposit);
35         
36         System.out.println("Deposit Complete: Current Balance is " + getCashInAccount());
37         
38     }
39     
40 }

• BankAccountFacade.java

 1 // The Facade Design Pattern decouples or separates the client 
 2 // from all of the sub components
 3 
 4 // The Facades aim is to simplify interfaces so you don't have 
 5 // to worry about what is going on under the hood
 6 
 7 public class BankAccountFacade {
 8     
 9     private int accountNumber;
10     private int securityCode;
11     
12     AccountNumberCheck acctChecker;
13     SecurityCodeCheck codeChecker;
14     FundsCheck fundChecker;
15     
16     WelcomeToBank bankWelcome;
17     
18     public BankAccountFacade(int newAcctNum, int newSecCode){
19         
20         accountNumber = newAcctNum;
21         securityCode = newSecCode;
22         
23         bankWelcome = new WelcomeToBank();
24         
25         acctChecker = new AccountNumberCheck();
26         codeChecker = new SecurityCodeCheck();
27         fundChecker = new FundsCheck();
28         
29     }
30     
31     public int getAccountNumber() { return accountNumber; }
32     
33     public int getSecurityCode() { return securityCode; }
34     
35     
36     public void withdrawCash(double cashToGet){
37         
38         if(acctChecker.accountActive(getAccountNumber()) &&
39                 codeChecker.isCodeCorrect(getSecurityCode()) &&
40                 fundChecker.haveEnoughMoney(cashToGet)) {
41                     
42                     System.out.println("Transaction Complete
");
43                     
44                 } else {
45                     
46                     System.out.println("Transaction Failed
");
47                     
48                 }
49         
50     }
51     
52     
53     public void depositCash(double cashToDeposit){
54         
55         if(acctChecker.accountActive(getAccountNumber()) &&
56                 codeChecker.isCodeCorrect(getSecurityCode())) {
57             
58                     fundChecker.makeDeposit(cashToDeposit);
59                     
60                     System.out.println("Transaction Complete
");
61                     
62                 } else {
63                     
64                     System.out.println("Transaction Failed
");
65                     
66                 }
67         
68     }
69     
70 }

• TestBankAccount.java

 1 public class TestBankAccount {
 2     
 3     public static void main(String[] args){
 4         
 5         BankAccountFacade accessingBank = new BankAccountFacade(12345678, 1234);
 6         
 7         accessingBank.withdrawCash(50.00);
 8         
 9         accessingBank.withdrawCash(990.00);
10         
11     }
12     
13 }

Bridge

What is the Bridge Design Pattern?

• Decouple an abstraction from its implementation so that the two can vary independently.

• The Bridge Design Pattern is very poorly explained.

• Everyone seems to explain it differently.

• Progressively adding functionality while separating out major differences using abstract classes.

When to use the Bridge Design Pattern?

• When you want to be able to change both the abstractions (abstract classes) and concrete classes independently.

• When you want the first abstract class to define rules (Abstract TV).

• The concrete class adds additional rules (Concrete TV).

• An abstract class has a reference to the device and it defines abstract methods that will be defined (Abstract Remote).

• The Concrete Remote defines the abstract methods required.

Sample Code

• EntertainmentDevice.java

 1 // Implementor
 2 // With the Bridge Design Pattern you create 2 layers of abstraction
 3 // In this example I'll have an abstract class representing
 4 // different types of devices. I also have an abstract class
 5 // that will represent different types of remote controls
 6 
 7 // This allows me to use an infinite variety of devices and remotes
 8 
 9 abstract class EntertainmentDevice {
10     
11     public int deviceState;
12     
13     public int maxSetting;
14     
15     public int volumeLevel = 0;
16     
17     public abstract void buttonFivePressed();
18     
19     public abstract void buttonSixPressed();
20     
21     public void deviceFeedback() {
22         
23         if(deviceState > maxSetting || deviceState < 0) { deviceState = 0; }
24         
25         System.out.println("On Channel " + deviceState);
26         
27     }
28     
29     public void buttonSevenPressed() {
30         
31         volumeLevel++;
32         
33         System.out.println("Volume at: " + volumeLevel);
34         
35     }
36     
37     public void buttonEightPressed() {
38         
39         volumeLevel--;
40         
41         System.out.println("Volume at: " + volumeLevel);
42         
43     }
44     
45 }

• TVDevice.java

 1 // Concrete Implementor
 2 
 3 // Here is an implementation of the EntertainmentDevice
 4 // abstract class. I'm specifying what makes it different
 5 // from other devices
 6 
 7 public class TVDevice extends EntertainmentDevice {
 8     
 9     public TVDevice(int newDeviceState, int newMaxSetting){
10         
11         deviceState = newDeviceState;
12         
13         maxSetting = newMaxSetting;
14         
15     }
16     
17     public void buttonFivePressed() {
18         
19         System.out.println("Channel Down");
20         
21         deviceState--;
22         
23     }
24 
25     public void buttonSixPressed() {
26         
27         System.out.println("Channel Up");
28         
29         deviceState++;
30         
31     }
32     
33 }

• RemoteButton.java

 1 // Abstraction
 2 
 3 // This is an abstract class that will represent numerous
 4 // ways to work with each device
 5 
 6 public abstract class RemoteButton{
 7     
 8     // A reference to a generic device using aggregation
 9     
10     private EntertainmentDevice theDevice;
11     
12     public RemoteButton(EntertainmentDevice newDevice){
13         
14         theDevice = newDevice;
15         
16     }
17     
18     public void buttonFivePressed() {
19         
20         theDevice.buttonFivePressed();
21         
22     }
23     
24     public void buttonSixPressed() {
25         
26         theDevice.buttonSixPressed();
27         
28     }
29     
30     public void deviceFeedback(){
31         
32         theDevice.deviceFeedback();
33         
34     }
35     
36     public abstract void buttonNinePressed();
37     
38 }

• TVRemoteMute.java

 1 // Refined Abstraction
 2 
 3 // If I decide I want to further extend the remote I can
 4 
 5 public class TVRemoteMute extends RemoteButton{
 6     
 7     public TVRemoteMute(EntertainmentDevice newDevice) {
 8         super(newDevice);
 9     }
10     
11     public void buttonNinePressed() {
12         
13         System.out.println("TV was Muted");
14         
15     }
16     
17 }

• TVRemotePause.java

 1 // Refined Abstraction
 2 
 3 // If I decide I want to further extend the remote I can
 4 
 5 public class TVRemotePause extends RemoteButton{
 6     
 7     public TVRemotePause(EntertainmentDevice newDevice) {
 8         super(newDevice);
 9     }
10     
11     public void buttonNinePressed() {
12         
13         System.out.println("TV was Paused");
14         
15     }
16     
17 }

• TestTheRemote.java

 1 public class TestTheRemote{
 2     
 3     public static void main(String[] args){
 4         
 5         RemoteButton theTV = new TVRemoteMute(new TVDevice(1, 200));
 6         
 7         RemoteButton theTV2 = new TVRemotePause(new TVDevice(1, 200));
 8         
 9         // HOMEWORK --------------
10         
11         RemoteButton theDVD = new DVDRemote(new DVDDevice(1,14));
12         
13         // -----------------------
14         
15         System.out.println("Test TV with Mute");
16         
17         theTV.buttonFivePressed();
18         theTV.buttonSixPressed();
19         theTV.buttonNinePressed();
20         
21         System.out.println("
Test TV with Pause");
22         
23         theTV2.buttonFivePressed();
24         theTV2.buttonSixPressed();
25         theTV2.buttonNinePressed();
26         theTV2.deviceFeedback();
27         
28         // HOMEWORK
29         
30         System.out.println("
Test DVD");
31         
32         theDVD.buttonFivePressed();
33         theDVD.buttonSixPressed();
34         theDVD.buttonNinePressed();
35         theDVD.buttonNinePressed();
36         
37     }
38     
39 }

Flyweight

What is the Flyweight Design Pattern?

• Used when you need to create a large number of similar objects.

• To reduce memory usage you share objects that are similar in some way rather than creating new ones.

• Intrinsic State: Color.

• Extrinsic State: Size.

Sample Code

• FlyWeightTest.java

  1 // The Flyweight design pattern is used when you need to
  2 // create a large number of similar objects
  3 
  4 // To reduce memory this pattern shares Objects that are 
  5 // the same rather than creating new ones
  6 
  7 import javax.swing.*;
  8 
  9 import java.awt.BorderLayout;
 10 import java.awt.Color;
 11 import java.awt.Graphics;
 12 
 13 import java.awt.event.ActionEvent;
 14 import java.awt.event.ActionListener;
 15 import java.util.Random;
 16 
 17 public class FlyWeightTest extends JFrame{
 18 
 19     private static final long serialVersionUID = 1L;
 20 
 21     JButton startDrawing;
 22     
 23     int windowWidth = 1750;
 24     int windowHeight = 1000;
 25     
 26     // A new rectangle is created only if a new color is needed
 27     
 28     Color[] shapeColor = {Color.orange, Color.red, Color.yellow,
 29             Color.blue, Color.pink, Color.cyan, Color.magenta,
 30             Color.black, Color.gray};
 31     
 32     public static void main(String[] args){
 33         
 34         new FlyWeightTest();
 35         
 36     }
 37     
 38     public FlyWeightTest(){
 39         
 40         // Create the frame, position it and handle closing it
 41         
 42         this.setSize(windowWidth,windowHeight);
 43         this.setLocationRelativeTo(null);
 44         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 45         this.setTitle("Flyweight Test");
 46         
 47         JPanel contentPane = new JPanel();
 48         
 49         contentPane.setLayout(new BorderLayout());
 50         
 51         final JPanel  drawingPanel  = new JPanel();
 52         
 53         startDrawing = new JButton("Button 1");
 54         
 55         contentPane.add(drawingPanel,  BorderLayout.CENTER);
 56         
 57         contentPane.add(startDrawing, BorderLayout.SOUTH);
 58         
 59         startDrawing.addActionListener(new ActionListener() {
 60             
 61             public void actionPerformed(ActionEvent event) {
 62                 Graphics g = drawingPanel.getGraphics();
 63                 
 64                 
 65                 long startTime = System.currentTimeMillis();
 66                 
 67                 
 68                 for(int i=0; i < 100000; ++i) {
 69                     
 70                     // 
 71                     // Uses rectangles stored in the HashMap to
 72                     // speed up the program
 73                     
 74                     MyRect rect = RectFactory.getRect(getRandColor());
 75                     rect.draw(g, getRandX(), getRandY(), 
 76                             getRandX(), getRandY());
 77                     
 78                     // 
 79                     /*
 80                     MyRect rect = new MyRect(getRandColor(), getRandX(), getRandY(), getRandX(), getRandY());
 81                     rect.draw(g);
 82                     */
 83                     
 84 
 85                     // 
 86                     /*
 87                     g.setColor(getRandColor());
 88                     g.fillRect(getRandX(), getRandY(), getRandX(), getRandY());
 89                     */
 90                     
 91                     
 92                 }
 93                 
 94                 long endTime = System.currentTimeMillis();
 95 
 96                 System.out.println("That took " + (endTime - startTime) + " milliseconds");
 97                 
 98              }
 99           });
100         
101         this.add(contentPane);
102         
103         this.setVisible(true);
104         
105     }
106     
107     // Picks random x & y coordinates
108     
109     private int getRandX(){ return (int)(Math.random()*windowWidth); }
110     
111     private int getRandY(){ return (int)(Math.random()*windowHeight); }
112     
113     // Picks a random Color from the 9 available
114     
115     private Color getRandColor(){ 
116         Random randomGenerator = new Random();
117         
118         int randInt = randomGenerator.nextInt(9);
119         
120         return shapeColor[randInt]; 
121         
122     }
123     
124 }

• MyRect.java

 1 import java.awt.*;
 2 public class MyRect {
 3    private Color color = Color.black;
 4    private int x, y, x2, y2;
 5    
 6    public MyRect(Color color) {
 7        
 8        this.color = color;
 9        
10    }
11    
12    public void draw(Graphics g, int upperX, int upperY, int lowerX, int lowerY) {
13           g.setColor(color);
14           g.fillRect(upperX, upperY, lowerX, lowerY);
15    }
16    
17    /* Original forces creation of a rectangle every time
18      
19    public MyRect(Color color, int upperX, int upperY, int lowerX, int lowerY) {
20       this.color = color;
21       this.x = upperX;   
22       this.y = upperY;
23       this.x2 = lowerX; 
24       this.y2 = lowerY;
25    }
26    
27    public void draw(Graphics g) {
28       g.setColor(color);
29       g.fillRect(x, y, x2, y2);
30    }
31    */
32 }

• RectFactory.java

 1 // This factory only creates a new rectangle if it 
 2 // uses a color not previously used
 3 
 4 // Intrinsic State: Color
 5 // Extrinsic State: X & Y Values
 6 
 7 import java.util.HashMap;
 8 import java.awt.Color;
 9 public class RectFactory {
10     
11     // The HashMap uses the color as the key for every 
12     // rectangle it will make up to 8 total
13     
14     private static final HashMap<Color, MyRect> rectsByColor = new HashMap<Color, MyRect>();
15    
16     public static MyRect getRect(Color color) {
17         MyRect rect = (MyRect)rectsByColor.get(color);
18         
19         // Checks if a rectangle with a specific
20         // color has been made. If not it makes a
21         // new one, otherwise it returns one made already
22         
23         if(rect == null) {
24             rect = new MyRect(color);
25             
26             // Add new rectangle to HashMap
27             
28             rectsByColor.put(color, rect);
29          
30         }
31         return rect;
32     }
33 }

Proxy

What is the Proxy Design Pattern?

• Provide a class which will limit access to another class.

• You may do this for security reasons, because an Object is intensive to create, or is accessed from a remote location.

Sample Code

• ATMMachine.java

 1 public class ATMMachine implements GetATMData{
 2     
 3     
 4     public ATMState getYesCardState() { return hasCard; }
 5     public ATMState getNoCardState() { return noCard; }
 6     public ATMState getHasPin() { return hasCorrectPin; }
 7     public ATMState getNoCashState() { return atmOutOfMoney; }
 8     
 9     // NEW STUFF
10     
11     public ATMState getATMState() { return atmState; }
12     public int getCashInMachine() { return cashInMachine; }
13 }

• GetATMData.java

1 // This interface will contain just those methods
2 // that you want the proxy to provide access to
3 
4 public interface GetATMData {
5   public ATMState getATMState();
6   public int getCashInMachine();
7 }

• ATMProxy.java

 1 // In this situation the proxy both creates and destroys
 2 // an ATMMachine Object
 3 
 4 public class ATMProxy implements GetATMData {
 5 
 6     // Allows the user to access getATMState in the 
 7     // Object ATMMachine
 8     
 9     public ATMState getATMState() {
10         
11         ATMMachine realATMMachine = new ATMMachine();
12         
13         return realATMMachine.getATMState();
14     }
15 
16     // Allows the user to access getCashInMachine 
17     // in the Object ATMMachine
18     
19     public int getCashInMachine() {
20         
21         ATMMachine realATMMachine = new ATMMachine();
22         
23         return realATMMachine.getCashInMachine();
24         
25     }
26     
27 }

• TestATMMachine.java

 1 public class TestATMMachine {
 2     
 3     public static void main(String[] args){
 4         
 5         ATMMachine atmMachine = new ATMMachine();
 6         
 7         atmMachine.insertCard();
 8         
 9         atmMachine.ejectCard();
10         
11         atmMachine.insertCard();
12         
13         atmMachine.insertPin(1234);
14         
15         atmMachine.requestCash(2000);
16         
17         atmMachine.insertCard();
18         
19         atmMachine.insertPin(1234);
20         
21         // NEW STUFF : Proxy Design Pattern Code
22         // The interface limits access to just the methods you want
23         // made accessible
24 
25         GetATMData realATMMachine = new ATMMachine();
26         
27         GetATMData atmProxy = new ATMProxy();
28         
29         System.out.println("
Current ATM State " + atmProxy.getATMState());
30         
31         System.out.println("
Cash in ATM Machine $" + atmProxy.getCashInMachine());
32         
33         // The user can't perform this action because ATMProxy doesn't
34         // have access to that potentially harmful method
35         // atmProxy.setCashInMachine(10000);
36         
37     }
38     
39 }

• ATMState.java

1 public interface ATMState {
2     
3     void insertCard();
4     void ejectCard();
5     void insertPin(int pinEntered);
6     void requestCash(int cashToWithdraw);
7     
8 }

作者:netoxi
出处:http://www.cnblogs.com/netoxi
本文版权归作者和博客园共有,欢迎转载,未经同意须保留此段声明,且在文章页面明显位置给出原文连接。欢迎指正与交流。