目录
· Strategy
· When to use the Strategy Design Pattern?
· Observer
· When to use the Observer Design Pattern?
· Command
· What is the Command Design Pattern?
· Benefits of the Command Design Pattern.
· What is the Template Method Design Pattern?
· Iterator
· What is the Iterator Design Pattern?
· State
· What is the State Design Pattern?
· State Design Pattern Example.
· What is the Chain of Responsibility Design Pattern?
· What is the Interpreter Design Pattern?
· Mediator
· What is the Mediator Design Pattern?
· Memento
· What is the Memento Design Pattern?
· Visitor
· What is the Visitor Design Pattern?
Strategy
When to use the Strategy Design Pattern?
• When you want to define a class that will have one behavior that is similar to other behaviors in a list.
• I want the class object to be able to choose from
• Not Flying.
• Fly with Wings.
• Fly Super Fast.
• When you need to use one of several behaviors dynamically.
• Often reduces long lists of conditionals.
• Avoids duplicate code.
• Keeps class changes from forcing other class changes.
• Can hide complicated / secret code from the user.
• Negative: Increased number of objects / classes.
Sample Code
• Animal.java
1 public class Animal { 2 3 private String name; 4 private double height; 5 private int weight; 6 private String favFood; 7 private double speed; 8 private String sound; 9 10 // Instead of using an interface in a traditional way 11 // we use an instance variable that is a subclass 12 // of the Flys interface. 13 14 // Animal doesn't care what flyingType does, it just 15 // knows the behavior is available to its subclasses 16 17 // This is known as Composition : Instead of inheriting 18 // an ability through inheritance the class is composed 19 // with Objects with the right ability 20 21 // Composition allows you to change the capabilities of 22 // objects at run time! 23 24 public Flys flyingType; 25 26 public void setName(String newName){ name = newName; } 27 public String getName(){ return name; } 28 29 public void setHeight(double newHeight){ height = newHeight; } 30 public double getHeight(){ return height; } 31 32 public void setWeight(int newWeight){ 33 if (newWeight > 0){ 34 weight = newWeight; 35 } else { 36 System.out.println("Weight must be bigger than 0"); 37 } 38 } 39 public double getWeight(){ return weight; } 40 41 public void setFavFood(String newFavFood){ favFood = newFavFood; } 42 public String getFavFood(){ return favFood; } 43 44 public void setSpeed(double newSpeed){ speed = newSpeed; } 45 public double getSpeed(){ return speed; } 46 47 public void setSound(String newSound){ sound = newSound; } 48 public String getSound(){ return sound; } 49 50 /* BAD 51 * You don't want to add methods to the super class. 52 * You need to separate what is different between subclasses 53 * and the super class 54 public void fly(){ 55 56 System.out.println("I'm flying"); 57 58 } 59 */ 60 61 // Animal pushes off the responsibility for flying to flyingType 62 63 public String tryToFly(){ 64 65 return flyingType.fly(); 66 67 } 68 69 // If you want to be able to change the flyingType dynamically 70 // add the following method 71 72 public void setFlyingAbility(Flys newFlyType){ 73 74 flyingType = newFlyType; 75 76 } 77 78 }
• Dog.java
1 public class Dog extends Animal{ 2 3 public void digHole(){ 4 5 System.out.println("Dug a hole"); 6 7 } 8 9 public Dog(){ 10 11 super(); 12 13 setSound("Bark"); 14 15 // We set the Flys interface polymorphically 16 // This sets the behavior as a non-flying Animal 17 18 flyingType = new CantFly(); 19 20 } 21 22 /* BAD 23 * You could override the fly method, but we are breaking 24 * the rule that we need to abstract what is different to 25 * the subclasses 26 * 27 public void fly(){ 28 29 System.out.println("I can't fly"); 30 31 } 32 */ 33 34 }
• Bird.java
1 public class Bird extends Animal{ 2 3 // The constructor initializes all objects 4 5 public Bird(){ 6 7 super(); 8 9 setSound("Tweet"); 10 11 // We set the Flys interface polymorphically 12 // This sets the behavior as a non-flying Animal 13 14 flyingType = new ItFlys(); 15 16 } 17 18 }
• Flys.java
1 // The interface is implemented by many other 2 // subclasses that allow for many types of flying 3 // without effecting Animal, or Flys. 4 5 // Classes that implement new Flys interface 6 // subclasses can allow other classes to use 7 // that code eliminating code duplication 8 9 // I'm decoupling : encapsulating the concept that varies 10 11 public interface Flys { 12 13 String fly(); 14 15 } 16 17 // Class used if the Animal can fly 18 19 class ItFlys implements Flys{ 20 21 public String fly() { 22 23 return "Flying High"; 24 25 } 26 27 } 28 29 //Class used if the Animal can't fly 30 31 class CantFly implements Flys{ 32 33 public String fly() { 34 35 return "I can't fly"; 36 37 } 38 39 }
• AnimalPlay.java
1 public class AnimalPlay{ 2 3 public static void main(String[] args){ 4 5 Animal sparky = new Dog(); 6 Animal tweety = new Bird(); 7 8 System.out.println("Dog: " + sparky.tryToFly()); 9 10 System.out.println("Bird: " + tweety.tryToFly()); 11 12 // This allows dynamic changes for flyingType 13 14 sparky.setFlyingAbility(new ItFlys()); 15 16 System.out.println("Dog: " + sparky.tryToFly()); 17 18 } 19 20 }
Observer
When to use the Observer Design Pattern?
• When you need many other objects to receive an update when another object changes.
• Stock market with thousands of stocks needs to send updates to objects representing individual stocks.
• The Subject (publisher) sends many stocks to the Observers.
• The Observers (subscribers) takes the ones they want and use them.
• Loose coupling is a benefit.
• The Subject (publisher) doesn't need to know anything about the Observers (subscribers).
• Negatives: The Subject (publisher) may send updates that don't matter to the Observer (subscriber).
Sample Code
• Subject.java
1 // This interface handles adding, deleting and updating 2 // all observers 3 4 public interface Subject { 5 6 public void register(Observer o); 7 public void unregister(Observer o); 8 public void notifyObserver(); 9 10 }
• Observer.java
1 // The Observers update method is called when the Subject changes 2 3 public interface Observer { 4 5 public void update(double ibmPrice, double aaplPrice, double googPrice); 6 7 }
• StockGrabber.java
1 import java.util.ArrayList; 2 3 // Uses the Subject interface to update all Observers 4 5 public class StockGrabber implements Subject{ 6 7 private ArrayList<Observer> observers; 8 private double ibmPrice; 9 private double aaplPrice; 10 private double googPrice; 11 12 public StockGrabber(){ 13 14 // Creates an ArrayList to hold all observers 15 16 observers = new ArrayList<Observer>(); 17 } 18 19 public void register(Observer newObserver) { 20 21 // Adds a new observer to the ArrayList 22 23 observers.add(newObserver); 24 25 } 26 27 public void unregister(Observer deleteObserver) { 28 29 // Get the index of the observer to delete 30 31 int observerIndex = observers.indexOf(deleteObserver); 32 33 // Print out message (Have to increment index to match) 34 35 System.out.println("Observer " + (observerIndex+1) + " deleted"); 36 37 // Removes observer from the ArrayList 38 39 observers.remove(observerIndex); 40 41 } 42 43 public void notifyObserver() { 44 45 // Cycle through all observers and notifies them of 46 // price changes 47 48 for(Observer observer : observers){ 49 50 observer.update(ibmPrice, aaplPrice, googPrice); 51 52 } 53 } 54 55 // Change prices for all stocks and notifies observers of changes 56 57 public void setIBMPrice(double newIBMPrice){ 58 59 this.ibmPrice = newIBMPrice; 60 61 notifyObserver(); 62 63 } 64 65 public void setAAPLPrice(double newAAPLPrice){ 66 67 this.aaplPrice = newAAPLPrice; 68 69 notifyObserver(); 70 71 } 72 73 public void setGOOGPrice(double newGOOGPrice){ 74 75 this.googPrice = newGOOGPrice; 76 77 notifyObserver(); 78 79 } 80 81 }
• StockObserver.java
1 // Represents each Observer that is monitoring changes in the subject 2 3 public class StockObserver implements Observer { 4 5 private double ibmPrice; 6 private double aaplPrice; 7 private double googPrice; 8 9 // Static used as a counter 10 11 private static int observerIDTracker = 0; 12 13 // Used to track the observers 14 15 private int observerID; 16 17 // Will hold reference to the StockGrabber object 18 19 private Subject stockGrabber; 20 21 public StockObserver(Subject stockGrabber){ 22 23 // Store the reference to the stockGrabber object so 24 // I can make calls to its methods 25 26 this.stockGrabber = stockGrabber; 27 28 // Assign an observer ID and increment the static counter 29 30 this.observerID = ++observerIDTracker; 31 32 // Message notifies user of new observer 33 34 System.out.println("New Observer " + this.observerID); 35 36 // Add the observer to the Subjects ArrayList 37 38 stockGrabber.register(this); 39 40 } 41 42 // Called to update all observers 43 44 public void update(double ibmPrice, double aaplPrice, double googPrice) { 45 46 this.ibmPrice = ibmPrice; 47 this.aaplPrice = aaplPrice; 48 this.googPrice = googPrice; 49 50 printThePrices(); 51 52 } 53 54 public void printThePrices(){ 55 56 System.out.println(observerID + "\nIBM: " + ibmPrice + "\nAAPL: " + 57 aaplPrice + "\nGOOG: " + googPrice + "\n"); 58 59 } 60 61 }
• GrabStocks.java
1 public class GrabStocks{ 2 3 public static void main(String[] args){ 4 5 // Create the Subject object 6 // It will handle updating all observers 7 // as well as deleting and adding them 8 9 StockGrabber stockGrabber = new StockGrabber(); 10 11 // Create an Observer that will be sent updates from Subject 12 13 StockObserver observer1 = new StockObserver(stockGrabber); 14 15 stockGrabber.setIBMPrice(197.00); 16 stockGrabber.setAAPLPrice(677.60); 17 stockGrabber.setGOOGPrice(676.40); 18 19 StockObserver observer2 = new StockObserver(stockGrabber); 20 21 stockGrabber.setIBMPrice(197.00); 22 stockGrabber.setAAPLPrice(677.60); 23 stockGrabber.setGOOGPrice(676.40); 24 25 // Delete one of the observers 26 27 // stockGrabber.unregister(observer2); 28 29 stockGrabber.setIBMPrice(197.00); 30 stockGrabber.setAAPLPrice(677.60); 31 stockGrabber.setGOOGPrice(676.40); 32 33 // Create 3 threads using the Runnable interface 34 // GetTheStock implements Runnable, so it doesn't waste 35 // its one extendable class option 36 37 Runnable getIBM = new GetTheStock(stockGrabber, 2, "IBM", 197.00); 38 Runnable getAAPL = new GetTheStock(stockGrabber, 2, "AAPL", 677.60); 39 Runnable getGOOG = new GetTheStock(stockGrabber, 2, "GOOG", 676.40); 40 41 // Call for the code in run to execute 42 43 new Thread(getIBM).start(); 44 new Thread(getAAPL).start(); 45 new Thread(getGOOG).start(); 46 47 48 } 49 50 }
• GetTheStock.java
1 import java.text.DecimalFormat; 2 3 public class GetTheStock implements Runnable{ 4 5 // Could be used to set how many seconds to wait 6 // in Thread.sleep() below 7 8 // private int startTime; 9 private String stock; 10 private double price; 11 12 // Will hold reference to the StockGrabber object 13 14 private Subject stockGrabber; 15 16 public GetTheStock(Subject stockGrabber, int newStartTime, String newStock, double newPrice){ 17 18 // Store the reference to the stockGrabber object so 19 // I can make calls to its methods 20 21 this.stockGrabber = stockGrabber; 22 23 // startTime = newStartTime; Not used to have variable sleep time 24 stock = newStock; 25 price = newPrice; 26 27 } 28 29 public void run(){ 30 31 for(int i = 1; i <= 20; i++){ 32 33 try{ 34 35 // Sleep for 2 seconds 36 Thread.sleep(2000); 37 38 // Use Thread.sleep(startTime * 1000); to 39 // make sleep time variable 40 } 41 catch(InterruptedException e) 42 {} 43 44 // Generates a random number between -.03 and .03 45 46 double randNum = (Math.random() * (.06)) - .03; 47 48 // Formats decimals to 2 places 49 50 DecimalFormat df = new DecimalFormat("#.##"); 51 52 // Change the price and then convert it back into a double 53 54 price = Double.valueOf(df.format((price + randNum))); 55 56 if(stock == "IBM") ((StockGrabber) stockGrabber).setIBMPrice(price); 57 if(stock == "AAPL") ((StockGrabber) stockGrabber).setAAPLPrice(price); 58 if(stock == "GOOG") ((StockGrabber) stockGrabber).setGOOGPrice(price); 59 60 System.out.println(stock + ": " + df.format((price + randNum)) + 61 " " + df.format(randNum)); 62 63 System.out.println(); 64 65 } 66 } 67 68 }
Command
What is the Command Design Pattern?
• The command pattern is a behavioral design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time.
• This information includes the method name, the object that owns the method and values for the method parameters.
• Allows you to store lists of code that is executed at a later time or many times.
• Client says I want a specific Command to run when execute() is called on one of these encapsulated (hidden) objects.
• An object called the Invoker transfers this Command to another object called a Receiver to execute the right code.
• TurnTVOn - DeviceButton - TurnTVOn - Television.TurnTVOn()
Benefits of the Command Design Pattern.
• Allows you to set aside a list of commands for later use.
• A class is a great place to store procedures you want to be executed.
• You can store multiple commands in a class to use over and over.
• You can implement undo procedures for past commands.
• Negative: You create many small classes that store lists of commands.
Sample Code
• ElectronicDevice.java
1 public interface ElectronicDevice { 2 3 public void on(); 4 5 public void off(); 6 7 public void volumeUp(); 8 9 public void volumenDown(); 10 11 }
• Television.java(RECEIVER)
1 public class Television implements ElectronicDevice { 2 3 private int volume = 0; 4 5 public void on() { 6 7 System.out.println("TV is on"); 8 9 } 10 11 public void off() { 12 13 System.out.println("TV is off"); 14 15 } 16 17 public void volumeUp() { 18 19 volume++; 20 21 System.out.println("TV Volume is at: " + volume); 22 23 } 24 25 public void volumenDown() { 26 27 volume--; 28 29 System.out.println("TV Volume is at: " + volume); 30 31 } 32 33 }
• Command.java
1 // Each command you want to issue will implement 2 // the Command interface 3 4 public interface Command { 5 6 public void execute(); 7 8 // You may want to offer the option to undo a command 9 10 public void undo(); 11 12 }
• TurnTVOn.java(COMMAND)
1 public class TurnTVOn implements Command { 2 3 ElectronicDevice theDevice; 4 5 public TurnTVOn(ElectronicDevice newDevice){ 6 7 theDevice = newDevice; 8 9 } 10 11 public void execute() { 12 13 theDevice.on(); 14 15 } 16 17 public void undo() { 18 19 theDevice.off(); 20 21 } 22 23 }
• TurnTVOff.java(COMMAND)
1 public class TurnTVOff implements Command { 2 3 ElectronicDevice theDevice; 4 5 public TurnTVOff(ElectronicDevice newDevice){ 6 7 theDevice = newDevice; 8 9 } 10 11 public void execute() { 12 13 theDevice.off(); 14 15 } 16 17 // Used if you want to allow for undo 18 // Do the opposite of execute() 19 20 public void undo() { 21 22 theDevice.on(); 23 24 } 25 26 }
• TurnTVUp.java(COMMAND)
1 public class TurnTVUp implements Command { 2 3 ElectronicDevice theDevice; 4 5 public TurnTVUp(ElectronicDevice newDevice){ 6 7 theDevice = newDevice; 8 9 } 10 11 public void execute() { 12 13 theDevice.volumeUp(); 14 15 } 16 17 public void undo() { 18 19 theDevice.volumenDown(); 20 21 } 22 23 }
• DeviceButton.java(INVOKER)
1 // This is known as the invoker 2 // It has a method press() that when executed 3 // causes the execute method to be called 4 5 // The execute method for the Command interface then calls 6 // the method assigned in the class that implements the 7 // Command interface 8 9 public class DeviceButton{ 10 11 Command theCommand; 12 13 public DeviceButton(Command newCommand){ 14 15 theCommand = newCommand; 16 17 } 18 19 public void press(){ 20 21 theCommand.execute(); 22 23 } 24 25 // Now the remote can undo past commands 26 27 public void pressUndo(){ 28 29 theCommand.undo(); 30 31 } 32 33 }
• TVRemote.java
1 public class TVRemote { 2 3 public static ElectronicDevice getDevice(){ 4 5 return new Television(); 6 7 } 8 9 }
• PlayWithRemote.java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class PlayWithRemote{ 5 6 public static void main(String[] args){ 7 8 // Gets the ElectronicDevice to use 9 10 ElectronicDevice newDevice = TVRemote.getDevice(); 11 12 // TurnTVOn contains the command to turn on the tv 13 // When execute() is called on this command object 14 // it will execute the method on() in Television 15 16 TurnTVOn onCommand = new TurnTVOn(newDevice); 17 18 // Calling the execute() causes on() to execute in Television 19 20 DeviceButton onPressed = new DeviceButton(onCommand); 21 22 // When press() is called theCommand.execute(); executes 23 24 onPressed.press(); 25 26 //---------------------------------------------------------- 27 28 // Now when execute() is called off() of Television executes 29 30 TurnTVOff offCommand = new TurnTVOff(newDevice); 31 32 // Calling the execute() causes off() to execute in Television 33 34 onPressed = new DeviceButton(offCommand); 35 36 // When press() is called theCommand.execute(); executes 37 38 onPressed.press(); 39 40 //---------------------------------------------------------- 41 42 // Now when execute() is called volumeUp() of Television executes 43 44 TurnTVUp volUpCommand = new TurnTVUp(newDevice); 45 46 // Calling the execute() causes volumeUp() to execute in Television 47 48 onPressed = new DeviceButton(volUpCommand); 49 50 // When press() is called theCommand.execute(); executes 51 52 onPressed.press(); 53 onPressed.press(); 54 onPressed.press(); 55 56 //---------------------------------------------------------- 57 58 // Creating a TV and Radio to turn off with 1 press 59 60 Television theTV = new Television(); 61 62 Radio theRadio = new Radio(); 63 64 // Add the Electronic Devices to a List 65 66 List<ElectronicDevice> allDevices = new ArrayList<ElectronicDevice>(); 67 68 allDevices.add(theTV); 69 allDevices.add(theRadio); 70 71 // Send the List of Electronic Devices to TurnItAllOff 72 // where a call to run execute() on this function will 73 // call off() for each device in the list 74 75 TurnItAllOff turnOffDevices = new TurnItAllOff(allDevices); 76 77 // This calls for execute() to run which calls for off() to 78 // run for every ElectronicDevice 79 80 DeviceButton turnThemOff = new DeviceButton(turnOffDevices); 81 82 turnThemOff.press(); 83 84 //---------------------------------------------------------- 85 86 /* 87 * It is common to be able to undo a command in a command pattern 88 * To do so, DeviceButton will have a method called undo 89 * Undo() will perform the opposite action that the normal 90 * Command performs. undo() needs to be added to every class 91 * with an execute() 92 */ 93 94 turnThemOff.pressUndo(); 95 96 // To undo more than one command add them to a LinkedList 97 // using addFirst(). Then execute undo on each item until 98 // there are none left. (This is your Homework) 99 100 } 101 102 }
• Radio.java(RECEIVER)
1 public class Radio implements ElectronicDevice { 2 3 private int volume = 0; 4 5 public void on() { 6 7 System.out.println("Radio is on"); 8 9 } 10 11 public void off() { 12 13 System.out.println("Radio is off"); 14 15 } 16 17 public void volumeUp() { 18 19 volume++; 20 21 System.out.println("Radio Volume is at: " + volume); 22 23 } 24 25 public void volumenDown() { 26 27 volume--; 28 29 System.out.println("Radio Volume is at: " + volume); 30 31 } 32 33 }
• TurnItAllOff.java(COMMAND)
1 import java.util.List; 2 3 public class TurnItAllOff implements Command { 4 List<ElectronicDevice> theDevices; 5 6 public TurnItAllOff(List<ElectronicDevice> newDevices) { 7 theDevices = newDevices; 8 } 9 10 public void execute() { 11 12 for (ElectronicDevice device : theDevices) { 13 device.off(); 14 } 15 16 } 17 18 public void undo() { 19 20 for (ElectronicDevice device : theDevices) { 21 device.on(); 22 } 23 24 } 25 }
Template Method
What is the Template Method Design Pattern?
• Used to create a group of subclasses that have to execute a similar group of methods.
• You create an abstract class that contains a method called the Template Method.
• The Template Method contains a series of method calls that every subclass object will call.
• The subclass objects can override some of the method calls.
Sample Code
• ItalianHoagie.java
1 public class ItalianHoagie extends Hoagie{ 2 3 String[] meatUsed = { "Salami", "Pepperoni", "Capicola Ham" }; 4 String[] cheeseUsed = { "Provolone" }; 5 String[] veggiesUsed = { "Lettuce", "Tomatoes", "Onions", "Sweet Peppers" }; 6 String[] condimentsUsed = { "Oil", "Vinegar" }; 7 8 public void addMeat(){ 9 10 System.out.print("Adding the Meat: "); 11 12 for (String meat : meatUsed){ 13 14 System.out.print(meat + " "); 15 16 } 17 18 } 19 20 public void addCheese(){ 21 22 System.out.print("Adding the Cheese: "); 23 24 for (String cheese : cheeseUsed){ 25 26 System.out.print(cheese + " "); 27 28 } 29 30 } 31 32 public void addVegetables(){ 33 34 System.out.print("Adding the Vegetables: "); 35 36 for (String vegetable : veggiesUsed){ 37 38 System.out.print(vegetable + " "); 39 40 } 41 42 } 43 44 public void addCondiments(){ 45 46 System.out.print("Adding the Condiments: "); 47 48 for (String condiment : condimentsUsed){ 49 50 System.out.print(condiment + " "); 51 52 } 53 54 } 55 56 } 57 58 /* 59 public void makeSandwich(){ 60 61 cutBun(); 62 addMeat(); 63 addCheese(); 64 addVegetables(); 65 addCondiments(); 66 wrapTheHoagie(); 67 68 } 69 70 public void cutBun(){ 71 72 System.out.println("The Hoagie is Cut"); 73 74 } 75 76 public void addMeat(){ 77 78 System.out.println("Add Salami, Pepperoni and Capicola ham"); 79 80 } 81 82 public void addCheese(){ 83 84 System.out.println("Add Provolone"); 85 86 } 87 88 public void addVegetables(){ 89 90 System.out.println("Add Lettuce, Tomatoes, Onions and Sweet Peppers"); 91 92 } 93 94 public void addCondiments(){ 95 96 System.out.println("Add Oil and Vinegar"); 97 98 } 99 100 public void wrapTheHoagie(){ 101 102 System.out.println("Wrap the Hoagie"); 103 104 } 105 106 } 107 */
• Hoagie.java
1 // A Template Method Pattern contains a method that provides 2 // the steps of the algorithm. It allows subclasses to override 3 // some of the methods 4 5 public abstract class Hoagie { 6 7 boolean afterFirstCondiment = false; 8 9 // This is the Template Method 10 // Declare this method final to keep subclasses from 11 // changing the algorithm 12 13 final void makeSandwich(){ 14 15 cutBun(); 16 17 if(customerWantsMeat()){ 18 19 addMeat(); 20 21 // Here to handle new lines for spacing 22 afterFirstCondiment = true; 23 24 } 25 26 if(customerWantsCheese()){ 27 28 if(afterFirstCondiment) { System.out.print("\n"); } 29 30 addCheese(); 31 32 afterFirstCondiment = true; 33 34 } 35 36 if(customerWantsVegetables()){ 37 38 if(afterFirstCondiment) { System.out.print("\n"); } 39 40 addVegetables(); 41 42 afterFirstCondiment = true; 43 44 } 45 46 if(customerWantsCondiments()){ 47 48 if(afterFirstCondiment) { System.out.print("\n"); } 49 50 addCondiments(); 51 52 afterFirstCondiment = true; 53 54 } 55 56 wrapTheHoagie(); 57 58 } 59 60 // These methods must be overridden by the extending subclasses 61 62 abstract void addMeat(); 63 abstract void addCheese(); 64 abstract void addVegetables(); 65 abstract void addCondiments(); 66 67 public void cutBun(){ 68 69 System.out.println("The Hoagie is Cut"); 70 71 } 72 73 // These are called hooks 74 // If the user wants to override these they can 75 76 // Use abstract methods when you want to force the user 77 // to override and use a hook when you want it to be optional 78 79 boolean customerWantsMeat() { return true; } 80 boolean customerWantsCheese() { return true; } 81 boolean customerWantsVegetables() { return true; } 82 boolean customerWantsCondiments() { return true; } 83 84 public void wrapTheHoagie(){ 85 86 System.out.println("\nWrap the Hoagie"); 87 88 } 89 90 public void afterFirstCondiment(){ 91 92 System.out.println("\n"); 93 94 } 95 96 }
• VeggieHoagie.java
1 public class VeggieHoagie extends Hoagie{ 2 3 String[] veggiesUsed = { "Lettuce", "Tomatoes", "Onions", "Sweet Peppers" }; 4 String[] condimentsUsed = { "Oil", "Vinegar" }; 5 6 boolean customerWantsMeat() { return false; } 7 boolean customerWantsCheese() { return false; } 8 9 public void addVegetables(){ 10 11 System.out.print("Adding the Vegetables: "); 12 13 for (String vegetable : veggiesUsed){ 14 15 System.out.print(vegetable + " "); 16 17 } 18 19 } 20 21 public void addCondiments(){ 22 23 System.out.print("Adding the Condiments: "); 24 25 for (String condiment : condimentsUsed){ 26 27 System.out.print(condiment + " "); 28 29 } 30 31 } 32 33 void addMeat() {} 34 35 void addCheese() {} 36 37 38 }
• SandwichSculptor.java
1 public class SandwichSculptor { 2 3 public static void main(String[] args){ 4 5 ItalianHoagie cust12Hoagie = new ItalianHoagie(); 6 7 cust12Hoagie.makeSandwich(); 8 9 System.out.println(); 10 11 VeggieHoagie cust13Hoagie = new VeggieHoagie(); 12 13 cust13Hoagie.makeSandwich(); 14 15 } 16 17 }
Iterator
What is the Iterator Design Pattern?
• The Iterator pattern provides you with a uniform way to access different collections of objects.
• If you get an Array, ArrayList and Hashtable of objects, you pop out an iterator for each and treat them the same.
• This provides a uniform way to cycle through different collections.
• You can also write polymorphic code because you can refer to each collection of objects because they'll implement the same interface.
Sample Code
• SongInfo.java
1 // Will hold all of the info needed for each song 2 3 // I told all users to: 4 // 1. create a function named addSong() for adding song, band and release 5 // 2. create a function named getBestSongs() that will return the collection 6 // of songs 7 8 public class SongInfo{ 9 10 String songName; 11 String bandName; 12 int yearReleased; 13 14 public SongInfo(String newSongName, String newBandName, int newYearReleased){ 15 16 songName = newSongName; 17 bandName = newBandName; 18 yearReleased = newYearReleased; 19 20 } 21 22 public String getSongName(){ return songName; } 23 public String getBandName(){ return bandName; } 24 public int getYearReleased(){ return yearReleased; } 25 26 }
• SongsOfThe70s.java
1 import java.util.ArrayList; 2 import java.util.Iterator; 3 4 public class SongsOfThe70s implements SongIterator{ 5 6 // ArrayList holds SongInfo objects 7 8 ArrayList<SongInfo> bestSongs; 9 10 public SongsOfThe70s() { 11 12 bestSongs = new ArrayList<SongInfo>(); 13 14 addSong("Imagine", "John Lennon", 1971); 15 addSong("American Pie", "Don McLean", 1971); 16 addSong("I Will Survive", "Gloria Gaynor", 1979); 17 18 } 19 20 // Add a SongInfo object to the end of the ArrayList 21 22 public void addSong(String songName, String bandName, int yearReleased){ 23 24 SongInfo songInfo = new SongInfo(songName, bandName, yearReleased); 25 26 bestSongs.add(songInfo); 27 28 } 29 30 31 // Get rid of this 32 // Return the ArrayList filled with SongInfo Objects 33 34 public ArrayList<SongInfo> getBestSongs(){ 35 36 return bestSongs; 37 38 } 39 40 // NEW By adding this method I'll be able to treat all 41 // collections the same 42 43 public Iterator createIterator() { 44 // TODO Auto-generated method stub 45 return bestSongs.iterator(); 46 } 47 48 }
• SongsOfThe80s.java
1 import java.util.Arrays; 2 import java.util.Iterator; 3 4 public class SongsOfThe80s implements SongIterator{ 5 6 // Create an array of SongInfo Objects 7 8 SongInfo[] bestSongs; 9 10 // Used to increment to the next position in the array 11 12 int arrayValue = 0; 13 14 public SongsOfThe80s() { 15 16 bestSongs = new SongInfo[3]; 17 18 addSong("Roam", "B 52s", 1989); 19 addSong("Cruel Summer", "Bananarama", 1984); 20 addSong("Head Over Heels", "Tears For Fears", 1985); 21 22 } 23 24 // Add a SongInfo Object to the array and increment to the next position 25 26 public void addSong(String songName, String bandName, int yearReleased){ 27 28 SongInfo song = new SongInfo(songName, bandName, yearReleased); 29 30 bestSongs[arrayValue] = song; 31 32 arrayValue++; 33 34 } 35 36 // This is replaced by the Iterator 37 38 public SongInfo[] getBestSongs(){ 39 40 return bestSongs; 41 42 } 43 44 // NEW By adding this method I'll be able to treat all 45 // collections the same 46 47 @Override 48 public Iterator createIterator() { 49 // TODO Auto-generated method stub 50 return Arrays.asList(bestSongs).iterator(); 51 } 52 53 }
• SongsOfThe90s.java
1 import java.util.Hashtable; 2 import java.util.Iterator; 3 4 public class SongsOfThe90s implements SongIterator{ 5 6 // Create a Hashtable with an int as a key and SongInfo 7 // Objects 8 9 Hashtable<Integer, SongInfo> bestSongs = new Hashtable<Integer, SongInfo>(); 10 11 // Will increment the Hashtable key 12 13 int hashKey = 0; 14 15 public SongsOfThe90s() { 16 17 addSong("Losing My Religion", "REM", 1991); 18 addSong("Creep", "Radiohead", 1993); 19 addSong("Walk on the Ocean", "Toad The Wet Sprocket", 1991); 20 21 } 22 23 // Add a new SongInfo Object to the Hashtable and then increment 24 // the Hashtable key 25 26 public void addSong(String songName, String bandName, int yearReleased){ 27 28 SongInfo songInfo = new SongInfo(songName, bandName, yearReleased); 29 30 bestSongs.put(hashKey, songInfo); 31 32 hashKey++; 33 34 } 35 36 // This is replaced by the Iterator 37 // Return a Hashtable full of SongInfo Objects 38 39 public Hashtable<Integer, SongInfo> getBestSongs(){ 40 41 return bestSongs; 42 43 } 44 45 // NEW By adding this method I'll be able to treat all 46 // collections the same 47 48 public Iterator createIterator() { 49 // TODO Auto-generated method stub 50 return bestSongs.values().iterator(); 51 } 52 53 }
• DiscJockey.java
1 import java.util.ArrayList; 2 import java.util.Enumeration; 3 import java.util.Hashtable; 4 import java.util.Iterator; 5 6 public class DiscJockey { 7 8 SongsOfThe70s songs70s; 9 SongsOfThe80s songs80s; 10 SongsOfThe90s songs90s; 11 12 // NEW Passing in song iterators 13 14 SongIterator iter70sSongs; 15 SongIterator iter80sSongs; 16 SongIterator iter90sSongs; 17 18 /* OLD WAY 19 public DiscJockey(SongsOfThe70s newSongs70s, SongsOfThe80s newSongs80s, SongsOfThe90s newSongs90s) { 20 21 songs70s = newSongs70s; 22 songs80s = newSongs80s; 23 songs90s = newSongs90s; 24 25 } 26 */ 27 28 // NEW WAY Initialize the iterators 29 30 public DiscJockey(SongIterator newSongs70s, SongIterator newSongs80s, SongIterator newSongs90s) { 31 32 iter70sSongs = newSongs70s; 33 iter80sSongs = newSongs80s; 34 iter90sSongs = newSongs90s; 35 36 } 37 38 public void showTheSongs(){ 39 40 // Because the SongInfo Objects are stored in different 41 // collections everything must be handled on an individual 42 // basis. This is BAD! 43 44 ArrayList aL70sSongs = songs70s.getBestSongs(); 45 46 System.out.println("Songs of the 70s\n"); 47 48 for(int i=0; i < aL70sSongs.size(); i++){ 49 50 SongInfo bestSongs = (SongInfo) aL70sSongs.get(i); 51 52 System.out.println(bestSongs.getSongName()); 53 System.out.println(bestSongs.getBandName()); 54 System.out.println(bestSongs.getYearReleased() + "\n"); 55 56 } 57 58 SongInfo[] array80sSongs = songs80s.getBestSongs(); 59 60 System.out.println("Songs of the 80s\n"); 61 62 for(int j=0; j < array80sSongs.length; j++){ 63 64 SongInfo bestSongs = array80sSongs[j]; 65 66 System.out.println(bestSongs.getSongName()); 67 System.out.println(bestSongs.getBandName()); 68 System.out.println(bestSongs.getYearReleased() + "\n"); 69 70 } 71 72 Hashtable<Integer, SongInfo> ht90sSongs = songs90s.getBestSongs(); 73 74 System.out.println("Songs of the 90s\n"); 75 76 for (Enumeration<Integer> e = ht90sSongs.keys(); e.hasMoreElements();) 77 { 78 SongInfo bestSongs = ht90sSongs.get(e.nextElement()); 79 80 System.out.println(bestSongs.getSongName()); 81 System.out.println(bestSongs.getBandName()); 82 System.out.println(bestSongs.getYearReleased() + "\n"); 83 84 } 85 86 } 87 88 // Now that I can treat everything as an Iterator it cleans up 89 // the code while allowing me to treat all collections as 1 90 91 public void showTheSongs2(){ 92 93 System.out.println("NEW WAY WITH ITERATOR\n"); 94 95 Iterator Songs70s = iter70sSongs.createIterator(); 96 Iterator Songs80s = iter80sSongs.createIterator(); 97 Iterator Songs90s = iter90sSongs.createIterator(); 98 99 System.out.println("Songs of the 70s\n"); 100 printTheSongs(Songs70s); 101 102 System.out.println("Songs of the 80s\n"); 103 printTheSongs(Songs80s); 104 105 System.out.println("Songs of the 90s\n"); 106 printTheSongs(Songs90s); 107 108 } 109 110 public void printTheSongs(Iterator iterator){ 111 112 while(iterator.hasNext()){ 113 114 SongInfo songInfo = (SongInfo) iterator.next(); 115 116 System.out.println(songInfo.getSongName()); 117 System.out.println(songInfo.getBandName()); 118 System.out.println(songInfo.getYearReleased() + "\n"); 119 120 } 121 122 } 123 124 }
• RadioStation.java
1 public class RadioStation { 2 3 public static void main(String[] args){ 4 5 SongsOfThe70s songs70s = new SongsOfThe70s(); 6 SongsOfThe80s songs80s = new SongsOfThe80s(); 7 SongsOfThe90s songs90s = new SongsOfThe90s(); 8 9 DiscJockey madMike = new DiscJockey(songs70s, songs80s, songs90s); 10 11 // madMike.showTheSongs(); 12 13 madMike.showTheSongs2(); 14 15 } 16 17 }
• SongIterator.java
1 import java.util.Iterator; 2 3 public interface SongIterator { 4 5 public Iterator createIterator(); 6 7 }
State
What is the State Design Pattern?
• Allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
• Context (Account): Maintains an instance of a ConcreteState subclass that defines the current state.
• State: Defines an interface for encapsulating the behavior associated with a particular state of the Context.
• Concrete State: Each subclass implements a behavior associated with a state of Context.
State Design Pattern Example.
• Think about all possible states for the ATM:
• HasCard
• NoCard
• HasPin
• NoCash
Sample Code
• ATMState.java
1 public interface ATMState { 2 3 // Different states expected 4 // HasCard, NoCard, HasPin, NoCash 5 6 void insertCard(); 7 8 void ejectCard(); 9 10 void insertPin(int pinEntered); 11 12 void requestCash(int cashToWithdraw); 13 14 }
• ATMMachine.java
1 public class ATMMachine { 2 3 ATMState hasCard; 4 ATMState noCard; 5 ATMState hasCorrectPin; 6 ATMState atmOutOfMoney; 7 8 ATMState atmState; 9 10 int cashInMachine = 2000; 11 boolean correctPinEntered = false; 12 13 public ATMMachine(){ 14 15 hasCard = new HasCard(this); 16 noCard = new NoCard(this); 17 hasCorrectPin = new HasPin(this); 18 atmOutOfMoney = new NoCash(this); 19 20 atmState = noCard; 21 22 if(cashInMachine < 0){ 23 24 atmState = atmOutOfMoney; 25 26 } 27 28 } 29 30 void setATMState(ATMState newATMState){ 31 32 atmState = newATMState; 33 34 } 35 36 public void setCashInMachine(int newCashInMachine){ 37 38 cashInMachine = newCashInMachine; 39 40 } 41 42 public void insertCard() { 43 44 atmState.insertCard(); 45 46 } 47 48 public void ejectCard() { 49 50 atmState.ejectCard(); 51 52 } 53 54 public void requestCash(int cashToWithdraw) { 55 56 atmState.requestCash(cashToWithdraw); 57 58 } 59 60 public void insertPin(int pinEntered){ 61 62 atmState.insertPin(pinEntered); 63 64 } 65 66 public ATMState getYesCardState() { return hasCard; } 67 public ATMState getNoCardState() { return noCard; } 68 public ATMState getHasPin() { return hasCorrectPin; } 69 public ATMState getNoCashState() { return atmOutOfMoney; } 70 71 }
• HasCard.java
1 public class HasCard implements ATMState { 2 3 ATMMachine atmMachine; 4 5 public HasCard(ATMMachine newATMMachine){ 6 7 atmMachine = newATMMachine; 8 9 } 10 11 public void insertCard() { 12 13 System.out.println("You can only insert one card at a time"); 14 15 } 16 17 public void ejectCard() { 18 19 System.out.println("Your card is ejected"); 20 atmMachine.setATMState(atmMachine.getNoCardState()); 21 22 } 23 24 public void requestCash(int cashToWithdraw) { 25 26 System.out.println("You have not entered your PIN"); 27 28 29 } 30 31 public void insertPin(int pinEntered) { 32 33 if(pinEntered == 1234){ 34 35 System.out.println("You entered the correct PIN"); 36 atmMachine.correctPinEntered = true; 37 atmMachine.setATMState(atmMachine.getHasPin()); 38 39 } else { 40 41 System.out.println("You entered the wrong PIN"); 42 atmMachine.correctPinEntered = false; 43 System.out.println("Your card is ejected"); 44 atmMachine.setATMState(atmMachine.getNoCardState()); 45 46 } 47 } 48 }
• NoCard.java
1 public class NoCard implements ATMState { 2 3 ATMMachine atmMachine; 4 5 public NoCard(ATMMachine newATMMachine){ 6 7 atmMachine = newATMMachine; 8 9 } 10 11 public void insertCard() { 12 13 System.out.println("Please enter your pin"); 14 atmMachine.setATMState(atmMachine.getYesCardState()); 15 16 } 17 18 public void ejectCard() { 19 20 System.out.println("You didn't enter a card"); 21 22 } 23 24 public void requestCash(int cashToWithdraw) { 25 26 System.out.println("You have not entered your card"); 27 28 } 29 30 public void insertPin(int pinEntered) { 31 32 System.out.println("You have not entered your card"); 33 34 } 35 }
• HasPin.java
1 public class HasPin implements ATMState { 2 3 ATMMachine atmMachine; 4 5 public HasPin(ATMMachine newATMMachine){ 6 7 atmMachine = newATMMachine; 8 9 } 10 11 public void insertCard() { 12 13 System.out.println("You already entered a card"); 14 15 } 16 17 public void ejectCard() { 18 19 System.out.println("Your card is ejected"); 20 atmMachine.setATMState(atmMachine.getNoCardState()); 21 22 } 23 24 public void requestCash(int cashToWithdraw) { 25 26 if(cashToWithdraw > atmMachine.cashInMachine){ 27 28 System.out.println("You don't have that much cash available"); 29 System.out.println("Your card is ejected"); 30 atmMachine.setATMState(atmMachine.getNoCardState()); 31 32 } else { 33 34 System.out.println(cashToWithdraw + " is provided by the machine"); 35 atmMachine.setCashInMachine(atmMachine.cashInMachine - cashToWithdraw); 36 37 System.out.println("Your card is ejected"); 38 atmMachine.setATMState(atmMachine.getNoCardState()); 39 40 if(atmMachine.cashInMachine <= 0){ 41 42 atmMachine.setATMState(atmMachine.getNoCashState()); 43 44 } 45 } 46 } 47 48 public void insertPin(int pinEntered) { 49 50 System.out.println("You already entered a PIN"); 51 52 } 53 }
• NoCash.java
1 public class NoCash implements ATMState { 2 3 ATMMachine atmMachine; 4 5 public NoCash(ATMMachine newATMMachine){ 6 7 atmMachine = newATMMachine; 8 9 } 10 11 public void insertCard() { 12 13 System.out.println("We don't have any money"); 14 System.out.println("Your card is ejected"); 15 16 } 17 18 public void ejectCard() { 19 20 System.out.println("We don't have any money"); 21 System.out.println("There is no card to eject"); 22 23 } 24 25 public void requestCash(int cashToWithdraw) { 26 27 System.out.println("We don't have any money"); 28 29 } 30 31 public void insertPin(int pinEntered) { 32 33 System.out.println("We don't have any money"); 34 35 } 36 }
• 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 } 22 }
Chain of Responsibility
What is the Chain of Responsibility Design Pattern?
• This pattern sends data to an object and if that object can't use it, it sends it to any number of other objects that may be able to use it.
• Create 4 objects that can either add, subtract, multiply, or divide.
• Send 2 numbers and a command and allow these 4 objects to decide which can handle the requested calculation.
Sample Code
• Chain.java
1 // The chain of responsibility pattern has a 2 // group of objects that are expected to between 3 // them be able to solve a problem. 4 // If the first Object can't solve it, it passes 5 // the data to the next Object in the chain 6 7 public interface Chain { 8 9 // Defines the next Object to receive the data 10 // if this Object can't process it 11 12 public void setNextChain(Chain nextChain); 13 14 // Either solves the problem or passes the data 15 // to the next Object in the chain 16 17 public void calculate(Numbers request); 18 19 }
• Numbers.java
1 // This object will contain 2 numbers and a 2 // calculation to perform in the form of a String 3 4 public class Numbers { 5 6 private int number1; 7 private int number2; 8 9 private String calculationWanted; 10 11 public Numbers(int newNumber1, int newNumber2, String calcWanted){ 12 13 number1 = newNumber1; 14 number2 = newNumber2; 15 calculationWanted = calcWanted; 16 17 } 18 19 public int getNumber1(){ return number1; } 20 public int getNumber2(){ return number2; } 21 public String getCalcWanted(){ return calculationWanted; } 22 23 }
• AddNumbers.java
1 public class AddNumbers implements Chain{ 2 3 private Chain nextInChain; 4 5 // Defines the next Object to receive the 6 // data if this one can't use it 7 8 public void setNextChain(Chain nextChain) { 9 10 nextInChain = nextChain; 11 12 } 13 14 // Tries to calculate the data, or passes it 15 // to the Object defined in method setNextChain() 16 17 public void calculate(Numbers request) { 18 19 if(request.getCalcWanted() == "add"){ 20 21 System.out.print(request.getNumber1() + " + " + request.getNumber2() + " = "+ 22 (request.getNumber1()+request.getNumber2())); 23 24 } else { 25 26 nextInChain.calculate(request); 27 28 } 29 30 } 31 }
• SubtractNumbers.java
1 public class SubtractNumbers implements Chain{ 2 3 private Chain nextInChain; 4 5 @Override 6 public void setNextChain(Chain nextChain) { 7 8 nextInChain = nextChain; 9 10 } 11 12 @Override 13 public void calculate(Numbers request) { 14 15 if(request.getCalcWanted() == "sub"){ 16 17 System.out.print(request.getNumber1() + " - " + request.getNumber2() + " = "+ 18 (request.getNumber1()-request.getNumber2())); 19 20 } else { 21 22 nextInChain.calculate(request); 23 24 } 25 26 } 27 28 29 30 }
• MultNumbers.java
1 public class MultNumbers implements Chain{ 2 3 private Chain nextInChain; 4 5 @Override 6 public void setNextChain(Chain nextChain) { 7 8 nextInChain = nextChain; 9 10 } 11 12 @Override 13 public void calculate(Numbers request) { 14 15 if(request.getCalcWanted() == "mult"){ 16 17 System.out.print(request.getNumber1() + " * " + request.getNumber2() + " = "+ 18 (request.getNumber1()*request.getNumber2())); 19 20 } else { 21 22 nextInChain.calculate(request); 23 24 } 25 26 } 27 28 29 30 }
• DivideNumbers.java
1 public class DivideNumbers implements Chain{ 2 3 private Chain nextInChain; 4 5 @Override 6 public void setNextChain(Chain nextChain) { 7 8 nextInChain = nextChain; 9 10 } 11 12 @Override 13 public void calculate(Numbers request) { 14 15 if(request.getCalcWanted() == "div"){ 16 17 System.out.print(request.getNumber1() + " / " + request.getNumber2() + " = "+ 18 (request.getNumber1()/request.getNumber2())); 19 20 } else { 21 22 System.out.print("Only works for add, sub, mult, and div"); 23 24 } 25 } 26 }
• TestCalcChain.java
1 public class TestCalcChain { 2 3 public static void main(String[] args){ 4 5 // Here I define all of the objects in the chain 6 7 Chain chainCalc1 = new AddNumbers(); 8 Chain chainCalc2 = new SubtractNumbers(); 9 Chain chainCalc3 = new MultNumbers(); 10 Chain chainCalc4 = new DivideNumbers(); 11 12 // Here I tell each object where to forward the 13 // data if it can't process the request 14 15 chainCalc1.setNextChain(chainCalc2); 16 chainCalc2.setNextChain(chainCalc3); 17 chainCalc3.setNextChain(chainCalc4); 18 19 // Define the data in the Numbers Object 20 // and send it to the first Object in the chain 21 22 Numbers request = new Numbers(4,2,"add"); 23 24 chainCalc1.calculate(request); 25 26 } 27 28 }
Interpreter
What is the Interpreter Design Pattern?
• "The Interpreter pattern is normally ignored."
• "This pattern is almost never used."
• I find it to be extremely useful if combined with Java Reflection techniques.
• It is used to convert one representation of data into another.
• The Context contains the information that will be interpreted.
• The Expression is an abstract class that defines all the methods needed to perform the different conversations.
• The Terminal or Concrete Expressions provide specific conversations on different types of data.
Sample Code
• ConversionContext.java
1 public class ConversionContext { 2 3 private String conversionQues = ""; 4 private String conversionResponse = ""; 5 private String fromConversion = ""; 6 private String toConversion = ""; 7 private double quantity; 8 9 String[] partsOfQues; 10 11 public ConversionContext(String input) 12 { 13 this.conversionQues = input; 14 15 partsOfQues = getInput().split(" "); 16 17 fromConversion = getCapitalized(partsOfQues[1]); 18 19 toConversion = getLowercase(partsOfQues[3]); 20 21 quantity = Double.valueOf(partsOfQues[0]); 22 23 conversionResponse = partsOfQues[0] + " "+ partsOfQues[1] + " equals "; 24 } 25 26 public String getInput() { return conversionQues; } 27 28 public String getFromConversion() { return fromConversion; } 29 30 public String getToConversion() { return toConversion; } 31 32 public String getResponse() { return conversionResponse; } 33 34 public double getQuantity() { return quantity; } 35 36 // Make String lowercase 37 38 public String getLowercase(String wordToLowercase){ 39 40 return wordToLowercase.toLowerCase(); 41 42 } 43 44 // Capitalizes the first letter of a word 45 46 public String getCapitalized(String wordToCapitalize){ 47 48 // Make characters lower case 49 50 wordToCapitalize = wordToCapitalize.toLowerCase(); 51 52 // Make the first character uppercase 53 54 wordToCapitalize = Character.toUpperCase(wordToCapitalize.charAt(0)) + wordToCapitalize.substring(1); 55 56 // Put s on the end if not there 57 58 int lengthOfWord = wordToCapitalize.length(); 59 60 if((wordToCapitalize.charAt(lengthOfWord -1)) != 's'){ 61 62 wordToCapitalize = new StringBuffer(wordToCapitalize).insert(lengthOfWord, "s").toString(); 63 64 } 65 66 return wordToCapitalize; 67 68 } 69 70 }
• Expression.java
1 public abstract class Expression { 2 3 public abstract String gallons(double quantity); 4 public abstract String quarts(double quantity); 5 public abstract String pints(double quantity); 6 public abstract String cups(double quantity); 7 public abstract String tablespoons(double quantity); 8 9 }
• Gallons.java
1 public class Gallons extends Expression{ 2 3 public String gallons(double quantity) { 4 5 return Double.toString(quantity); 6 } 7 8 public String quarts(double quantity) { 9 return Double.toString(quantity*4); 10 } 11 12 public String pints(double quantity) { 13 return Double.toString(quantity*8); 14 } 15 16 public String cups(double quantity) { 17 return Double.toString(quantity*16); 18 } 19 20 public String tablespoons(double quantity) { 21 return Double.toString(quantity*256); 22 } 23 24 }
• Quarts.java
1 public class Quarts extends Expression{ 2 3 public String gallons(double quantity) { 4 5 return Double.toString(quantity/4); 6 } 7 8 public String quarts(double quantity) { 9 return Double.toString(quantity); 10 } 11 12 public String pints(double quantity) { 13 return Double.toString(quantity*2); 14 } 15 16 public String cups(double quantity) { 17 return Double.toString(quantity*4); 18 } 19 20 public String tablespoons(double quantity) { 21 return Double.toString(quantity*64); 22 } 23 24 }
• Pints.java
1 public class Pints extends Expression{ 2 3 public String gallons(double quantity) { 4 5 return Double.toString(quantity/8); 6 } 7 8 public String quarts(double quantity) { 9 return Double.toString(quantity/2); 10 } 11 12 public String pints(double quantity) { 13 return Double.toString(quantity); 14 } 15 16 public String cups(double quantity) { 17 return Double.toString(quantity*2); 18 } 19 20 public String tablespoons(double quantity) { 21 return Double.toString(quantity*32); 22 } 23 24 }
• Cups.java
1 public class Cups extends Expression{ 2 3 public String gallons(double quantity) { 4 5 return Double.toString(quantity/16); 6 } 7 8 public String quarts(double quantity) { 9 return Double.toString(quantity/4); 10 } 11 12 public String pints(double quantity) { 13 return Double.toString(quantity/2); 14 } 15 16 public String cups(double quantity) { 17 return Double.toString(quantity); 18 } 19 20 public String tablespoons(double quantity) { 21 return Double.toString(quantity*16); 22 } 23 24 }
• Tablespoons.java
1 public class Tablespoons extends Expression{ 2 3 public String gallons(double quantity) { 4 5 return Double.toString(quantity/256); 6 } 7 8 public String quarts(double quantity) { 9 return Double.toString(quantity/64); 10 } 11 12 public String pints(double quantity) { 13 return Double.toString(quantity/32); 14 } 15 16 public String cups(double quantity) { 17 return Double.toString(quantity/16); 18 } 19 20 public String tablespoons(double quantity) { 21 return Double.toString(quantity); 22 } 23 24 }
• MeasurementConversion.java
1 import java.lang.reflect.*; 2 3 import javax.swing.*; 4 5 public class MeasurementConversion { 6 7 public static void main(String[] args){ 8 9 // Create pop up window that asks for a question 10 11 JFrame frame = new JFrame(); 12 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13 14 String questionAsked = JOptionPane.showInputDialog(frame, "What is your question"); 15 16 // Add the question to the context for analysis 17 18 ConversionContext question = new ConversionContext(questionAsked); 19 20 String fromConversion = question.getFromConversion(); 21 22 String toConversion = question.getToConversion(); 23 24 double quantity = question.getQuantity(); 25 26 try { 27 28 // Get class based on the from conversion string 29 30 Class tempClass = Class.forName(fromConversion); 31 32 // Get the constructor dynamically for the conversion string 33 34 Constructor con = tempClass.getConstructor(); 35 36 // Create a new instance of the object you want to convert from 37 38 Object convertFrom = (Expression) con.newInstance(); 39 40 // Define the method parameters expected by the method that 41 // will convert to your chosen unit of measure 42 43 Class[] methodParams = new Class[]{Double.TYPE}; 44 45 // Get the method dynamically that will be needed to convert 46 // into your chosen unit of measure 47 48 Method conversionMethod = tempClass.getMethod(toConversion, methodParams); 49 50 // Define the method parameters that will be passed to the above method 51 52 Object[] params = new Object[]{new Double(quantity)}; 53 54 // Get the quantity after the conversion 55 56 String toQuantity = (String) conversionMethod.invoke(convertFrom, params); 57 58 // Print the results 59 60 String answerToQues = question.getResponse() + 61 toQuantity + " " + toConversion; 62 63 JOptionPane.showMessageDialog(null,answerToQues); 64 65 // Closes the frame after OK is clicked 66 67 frame.dispose(); 68 69 } catch (ClassNotFoundException e) { 70 // TODO Auto-generated catch block 71 e.printStackTrace(); 72 } catch (NoSuchMethodException e) { 73 // TODO Auto-generated catch block 74 e.printStackTrace(); 75 } catch (SecurityException e) { 76 // TODO Auto-generated catch block 77 e.printStackTrace(); 78 } catch (InstantiationException e) { 79 // TODO Auto-generated catch block 80 e.printStackTrace(); 81 } catch (IllegalAccessException e) { 82 // TODO Auto-generated catch block 83 e.printStackTrace(); 84 } catch (IllegalArgumentException e) { 85 // TODO Auto-generated catch block 86 e.printStackTrace(); 87 } catch (InvocationTargetException e) { 88 // TODO Auto-generated catch block 89 e.printStackTrace(); 90 } 91 92 } 93 94 }
Mediator
What is the Mediator Design Pattern?
• It is used to handle communication between related objects (Colleagues).
• All communication is handled by the Mediator and the Colleagues don't need to know anything about each other.
• GOF: Allows loose coupling by encapsulating the way disparate sets of objects interact and communicate with each other. Allows for the actions of each object set to vary independently of one another.
Sample Code
• StockOffer.java
1 public class StockOffer{ 2 3 private int stockShares = 0; 4 private String stockSymbol = ""; 5 private int colleagueCode = 0; 6 7 public StockOffer(int numOfShares, String stock, int collCode){ 8 9 stockShares = numOfShares; 10 stockSymbol = stock; 11 colleagueCode = collCode; 12 13 } 14 15 public int getstockShares() { return stockShares; } 16 public String getStockSymbol() { return stockSymbol; } 17 public int getCollCode() { return colleagueCode; } 18 19 }
• Colleague.java
1 public abstract class Colleague{ 2 3 private Mediator mediator; 4 private int colleagueCode; 5 6 7 public Colleague(Mediator newMediator){ 8 mediator = newMediator; 9 10 mediator.addColleague(this); 11 12 } 13 14 public void saleOffer(String stock, int shares){ 15 16 mediator.saleOffer(stock, shares, this.colleagueCode); 17 18 } 19 20 public void buyOffer(String stock, int shares){ 21 22 mediator.buyOffer(stock, shares, this.colleagueCode); 23 24 } 25 26 public void setCollCode(int collCode){ colleagueCode = collCode; } 27 28 29 }
• GormanSlacks.java
1 public class GormanSlacks extends Colleague{ 2 3 public GormanSlacks(Mediator newMediator) { 4 super(newMediator); 5 6 System.out.println("Gorman Slacks signed up with the stockexchange\n"); 7 8 } 9 10 }
• JTPoorman.java
1 public class JTPoorman extends Colleague{ 2 3 public JTPoorman(Mediator newMediator) { 4 super(newMediator); 5 6 System.out.println("JT Poorman signed up with the stockexchange\n"); 7 8 } 9 10 }
• Mediator.java
1 public interface Mediator { 2 3 public void saleOffer(String stock, int shares, int collCode); 4 5 public void buyOffer(String stock, int shares, int collCode); 6 7 public void addColleague(Colleague colleague); 8 9 }
• StockMediator.java
1 import java.util.ArrayList; 2 3 public class StockMediator implements Mediator{ 4 5 private ArrayList<Colleague> colleagues; 6 private ArrayList<StockOffer> stockBuyOffers; 7 private ArrayList<StockOffer> stockSaleOffers; 8 9 private int colleagueCodes = 0; 10 11 public StockMediator(){ 12 13 colleagues = new ArrayList<Colleague>(); 14 stockBuyOffers = new ArrayList<StockOffer>(); 15 stockSaleOffers = new ArrayList<StockOffer>(); 16 } 17 18 public void addColleague(Colleague newColleague){ 19 20 colleagues.add(newColleague); 21 22 colleagueCodes++; 23 24 newColleague.setCollCode(colleagueCodes); 25 26 } 27 28 public void saleOffer(String stock, int shares, int collCode) { 29 30 boolean stockSold = false; 31 32 for(StockOffer offer: stockBuyOffers){ 33 34 if((offer.getStockSymbol() == stock) && (offer.getstockShares() == shares)){ 35 36 System.out.println(shares + " shares of " + stock + 37 " sold to colleague code " + offer.getCollCode()); 38 39 stockBuyOffers.remove(offer); 40 41 stockSold = true; 42 43 } 44 45 if(stockSold){ break; } 46 47 } 48 49 if(!stockSold) { 50 51 System.out.println(shares + " shares of " + stock + 52 " added to inventory"); 53 54 StockOffer newOffering = new StockOffer(shares, stock, collCode); 55 56 stockSaleOffers.add(newOffering); 57 58 } 59 60 } 61 62 public void buyOffer(String stock, int shares, int collCode) { 63 64 boolean stockBought = false; 65 66 for(StockOffer offer: stockSaleOffers){ 67 68 if((offer.getStockSymbol() == stock) && (offer.getstockShares() == shares)){ 69 70 System.out.println(shares + " shares of " + stock + 71 " bought by colleague code " + offer.getCollCode()); 72 73 stockSaleOffers.remove(offer); 74 75 stockBought = true; 76 77 } 78 79 if(stockBought){ break; } 80 81 } 82 83 if(!stockBought) { 84 85 System.out.println(shares + " shares of " + stock + 86 " added to inventory"); 87 88 StockOffer newOffering = new StockOffer(shares, stock, collCode); 89 90 stockBuyOffers.add(newOffering); 91 92 } 93 94 } 95 96 public void getstockOfferings(){ 97 98 System.out.println("\nStocks for Sale"); 99 100 for(StockOffer offer: stockSaleOffers){ 101 102 System.out.println(offer.getstockShares() + " of " + offer.getStockSymbol()); 103 104 } 105 106 System.out.println("\nStock Buy Offers"); 107 108 for(StockOffer offer: stockBuyOffers){ 109 110 System.out.println(offer.getstockShares() + " of " + offer.getStockSymbol()); 111 112 } 113 114 } 115 116 }
• TestStockMediator.java
1 public class TestStockMediator{ 2 3 public static void main(String[] args){ 4 5 StockMediator nyse = new StockMediator(); 6 7 GormanSlacks broker = new GormanSlacks(nyse); 8 9 JTPoorman broker2 = new JTPoorman(nyse); 10 11 broker.saleOffer("MSFT", 100); 12 broker.saleOffer("GOOG", 50); 13 14 broker2.buyOffer("MSFT", 100); 15 broker2.saleOffer("NRG", 10); 16 17 broker.buyOffer("NRG", 10); 18 19 nyse.getstockOfferings(); 20 21 } 22 23 }
Memento
What is the Memento Design Pattern?
• A way to store previous states of an object easily.
• Memento: The basic object that is stored in different states.
• Originator: Sets and Gets values from the currently targeted Memento. Creates new mementos and assign current values to them.
• Caretaker: Holds an ArrayList that contains all previous versions of the Memento. It can store and retrieve stored Mementos.
Sample Code
• Memento.java
1 // Memento Design Pattern 2 // Used stores an objects state at a point in time 3 // so it can be returned to that state later. It 4 // simply allows you to undo/redo changes on an Object 5 6 public class Memento { 7 8 // The article stored in memento Object 9 10 private String article; 11 12 // Save a new article String to the memento Object 13 14 public Memento(String articleSave) { article = articleSave; } 15 16 // Return the value stored in article 17 18 public String getSavedArticle() { return article; } 19 20 }
• Originator.java
1 // Memento Design Pattern 2 3 public class Originator{ 4 5 private String article; 6 7 // Sets the value for the article 8 9 public void set(String newArticle) { 10 System.out.println("From Originator: Current Version of Article\n"+newArticle+ "\n"); 11 this.article = newArticle; 12 } 13 14 // Creates a new Memento with a new article 15 16 public Memento storeInMemento() { 17 System.out.println("From Originator: Saving to Memento"); 18 return new Memento(article); 19 } 20 21 // Gets the article currently stored in memento 22 23 public String restoreFromMemento(Memento memento) { 24 25 article = memento.getSavedArticle(); 26 27 System.out.println("From Originator: Previous Article Saved in Memento\n"+article + "\n"); 28 29 return article; 30 31 } 32 33 }
• Caretaker.java
1 // Memento Design Pattern Tutorial 2 3 import java.util.ArrayList; 4 5 class Caretaker { 6 7 // Where all mementos are saved 8 9 ArrayList<Memento> savedArticles = new ArrayList<Memento>(); 10 11 // Adds memento to the ArrayList 12 13 public void addMemento(Memento m) { savedArticles.add(m); } 14 15 // Gets the memento requested from the ArrayList 16 17 public Memento getMemento(int index) { return savedArticles.get(index); } 18 }
• TestMemento.java
1 // Memento Design Pattern Tutorial 2 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 6 import javax.swing.*; 7 8 public class TestMemento extends JFrame{ 9 public static void main(String[] args) { 10 11 new TestMemento(); 12 13 } 14 15 private JButton saveBut, undoBut, redoBut; 16 17 // JTextArea(rows, columns) 18 19 private JTextArea theArticle = new JTextArea(40,60); 20 21 // --------------------------------------------- 22 23 // Create a caretaker that contains the ArrayList 24 // with all the articles in it. It can add and 25 // retrieve articles from the ArrayList 26 27 Caretaker caretaker = new Caretaker(); 28 29 // The originator sets the value for the article, 30 // creates a new memento with a new article, and 31 // gets the article stored in the current memento 32 33 Originator originator = new Originator(); 34 35 int saveFiles = 0, currentArticle = 0; 36 37 // --------------------------------------------- 38 39 public TestMemento(){ 40 41 // Set basic information for the panel that will 42 // hold all the GUI elements 43 44 this.setSize(750,780); 45 this.setTitle("Memento Design Pattern"); 46 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 47 48 JPanel panel1 = new JPanel(); 49 50 // Add label to the panel 51 52 panel1.add(new JLabel("Article")); 53 54 // Add JTextArea to the panel 55 56 panel1.add(theArticle); 57 58 // Add the buttons & ButtonListeners to the panel 59 60 ButtonListener saveListener = new ButtonListener(); 61 ButtonListener undoListener = new ButtonListener(); 62 ButtonListener redoListener = new ButtonListener(); 63 64 saveBut = new JButton("Save"); 65 saveBut.addActionListener(saveListener); 66 67 undoBut = new JButton("Undo"); 68 undoBut.addActionListener(undoListener); 69 70 redoBut = new JButton("Redo"); 71 redoBut.addActionListener(redoListener); 72 73 panel1.add(saveBut); 74 panel1.add(undoBut); 75 panel1.add(redoBut); 76 77 // Add panel to the frame that shows on screen 78 79 this.add(panel1); 80 81 this.setVisible(true); 82 83 } 84 85 class ButtonListener implements ActionListener { 86 87 public void actionPerformed(ActionEvent e) { 88 89 if(e.getSource() == saveBut){ 90 91 // Get text in JTextArea 92 93 String textInTextArea = theArticle.getText(); 94 95 // Set the value for the current memento 96 97 originator.set(textInTextArea); 98 99 // Add new article to the ArrayList 100 101 caretaker.addMemento( originator.storeInMemento() ); 102 103 // saveFiles monitors how many articles are saved 104 // currentArticle monitors the current article displayed 105 106 saveFiles++; 107 currentArticle++; 108 109 System.out.println("Save Files " + saveFiles); 110 111 // Make undo clickable 112 113 undoBut.setEnabled(true); 114 115 } else 116 117 if(e.getSource() == undoBut){ 118 119 if(currentArticle >= 1){ 120 121 // Decrement to the current article displayed 122 123 currentArticle--; 124 125 // Get the older article saved and display it in JTextArea 126 127 String textBoxString = originator.restoreFromMemento( caretaker.getMemento(currentArticle) ); 128 129 theArticle.setText(textBoxString); 130 131 // Make Redo clickable 132 133 redoBut.setEnabled(true); 134 135 } else { 136 137 // Don't allow user to click Undo 138 139 undoBut.setEnabled(false); 140 141 } 142 143 } else 144 145 if(e.getSource() == redoBut){ 146 147 if((saveFiles - 1) > currentArticle){ 148 149 // Increment to the current article displayed 150 151 currentArticle++; 152 153 // Get the newer article saved and display it in JTextArea 154 155 String textBoxString = originator.restoreFromMemento( caretaker.getMemento(currentArticle) ); 156 157 theArticle.setText(textBoxString); 158 159 // Make undo clickable 160 161 undoBut.setEnabled(true); 162 163 } else { 164 165 // Don't allow user to click Redo 166 167 redoBut.setEnabled(false); 168 169 } 170 171 } 172 173 } 174 175 } 176 177 }
Visitor
What is the Visitor Design Pattern?
• Allows you to add methods to classes of different types without much altering to those classes.
• You can make completely different methods depending on the class used.
• Allows you to define external classes that can extend other classes without majorly editing them.
Sample Code
• Visitor.java
1 // The visitor pattern is used when you have to perform 2 // the same action on many objects of different types 3 4 interface Visitor { 5 6 // Created to automatically use the right 7 // code based on the Object sent 8 // Method Overloading 9 10 public double visit(Liquor liquorItem); 11 12 public double visit(Tobacco tobaccoItem); 13 14 public double visit(Necessity necessityItem); 15 16 }
• TaxVisitor.java
1 import java.text.DecimalFormat; 2 3 // Concrete Visitor Class 4 5 class TaxVisitor implements Visitor { 6 7 // This formats the item prices to 2 decimal places 8 9 DecimalFormat df = new DecimalFormat("#.##"); 10 11 // This is created so that each item is sent to the 12 // right version of visit() which is required by the 13 // Visitor interface and defined below 14 15 public TaxVisitor() { 16 } 17 18 // Calculates total price based on this being taxed 19 // as a liquor item 20 21 public double visit(Liquor liquorItem) { 22 System.out.println("Liquor Item: Price with Tax"); 23 return Double.parseDouble(df.format((liquorItem.getPrice() * .18) + liquorItem.getPrice())); 24 } 25 26 // Calculates total price based on this being taxed 27 // as a tobacco item 28 29 public double visit(Tobacco tobaccoItem) { 30 System.out.println("Tobacco Item: Price with Tax"); 31 return Double.parseDouble(df.format((tobaccoItem.getPrice() * .32) + tobaccoItem.getPrice())); 32 } 33 34 // Calculates total price based on this being taxed 35 // as a necessity item 36 37 public double visit(Necessity necessityItem) { 38 System.out.println("Necessity Item: Price with Tax"); 39 return Double.parseDouble(df.format(necessityItem.getPrice())); 40 } 41 42 }
• Visitable.java
1 interface Visitable { 2 3 // Allows the Visitor to pass the object so 4 // the right operations occur on the right 5 // type of object. 6 7 // accept() is passed the same visitor object 8 // but then the method visit() is called using 9 // the visitor object. The right version of visit() 10 // is called because of method overloading 11 12 public double accept(Visitor visitor); 13 14 }
• Liquor.java
1 class Liquor implements Visitable { 2 3 private double price; 4 5 Liquor(double item) { 6 price = item; 7 } 8 9 public double accept(Visitor visitor) { 10 return visitor.visit(this); 11 } 12 13 public double getPrice() { 14 return price; 15 } 16 17 }
• Necessity.java
1 class Necessity implements Visitable { 2 3 private double price; 4 5 Necessity(double item) { 6 price = item; 7 } 8 9 public double accept(Visitor visitor) { 10 return visitor.visit(this); 11 } 12 13 public double getPrice() { 14 return price; 15 } 16 17 }
• Tobacco.java
1 class Tobacco implements Visitable { 2 3 private double price; 4 5 Tobacco(double item) { 6 price = item; 7 } 8 9 public double accept(Visitor visitor) { 10 return visitor.visit(this); 11 } 12 13 public double getPrice() { 14 return price; 15 } 16 17 }
• TaxHolidayVisitor.java
1 import java.text.DecimalFormat; 2 3 // Concrete Visitor Class 4 5 class TaxHolidayVisitor implements Visitor { 6 7 // This formats the item prices to 2 decimal places 8 9 DecimalFormat df = new DecimalFormat("#.##"); 10 11 // This is created so that each item is sent to the 12 // right version of visit() which is required by the 13 // Visitor interface and defined below 14 15 public TaxHolidayVisitor() { 16 } 17 18 // Calculates total price based on this being taxed 19 // as a liquor item 20 21 public double visit(Liquor liquorItem) { 22 System.out.println("Liquor Item: Price with Tax"); 23 return Double.parseDouble(df.format((liquorItem.getPrice() * .10) + liquorItem.getPrice())); 24 } 25 26 // Calculates total price based on this being taxed 27 // as a tobacco item 28 29 public double visit(Tobacco tobaccoItem) { 30 System.out.println("Tobacco Item: Price with Tax"); 31 return Double.parseDouble(df.format((tobaccoItem.getPrice() * .30) + tobaccoItem.getPrice())); 32 } 33 34 // Calculates total price based on this being taxed 35 // as a necessity item 36 37 public double visit(Necessity necessityItem) { 38 System.out.println("Necessity Item: Price with Tax"); 39 return Double.parseDouble(df.format(necessityItem.getPrice())); 40 } 41 42 }
• VisitorTest.java
1 public class VisitorTest { 2 public static void main(String[] args) { 3 4 TaxVisitor taxCalc = new TaxVisitor(); 5 TaxHolidayVisitor taxHolidayCalc = new TaxHolidayVisitor(); 6 7 Necessity milk = new Necessity(3.47); 8 Liquor vodka = new Liquor(11.99); 9 Tobacco cigars = new Tobacco(19.99); 10 11 System.out.println(milk.accept(taxCalc) + "\n"); 12 System.out.println(vodka.accept(taxCalc) + "\n"); 13 System.out.println(cigars.accept(taxCalc) + "\n"); 14 15 System.out.println("TAX HOLIDAY PRICES\n"); 16 17 System.out.println(milk.accept(taxHolidayCalc) + "\n"); 18 System.out.println(vodka.accept(taxHolidayCalc) + "\n"); 19 System.out.println(cigars.accept(taxHolidayCalc) + "\n"); 20 21 } 22 }
作者:netoxi
出处:http://www.cnblogs.com/netoxi
本文版权归作者和博客园共有,欢迎转载,未经同意须保留此段声明,且在文章页面明显位置给出原文连接。欢迎指正与交流。