zoukankan      html  css  js  c++  java
  • 面向对象-设计模式-行为型

    面向对象-设计模式-行为型

     

          日暮乡关何处是?烟波江上使人愁。

     

    简介:面向对象-设计模式-行为型。

    一、概述

    何谓设计模式

    设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

    设计模式的好处&学习目的

    1、为了代码可重用行、让代码更易被他人理解、保证代码的可靠性、使代码编写真正实现工程化;

    2、设计模式便于我们维护项目,增强系统的健壮性和可扩展性;

    3、设计模式还可以锻炼码农的设计思维、升华代码质量等。

    二、行为型

    责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式、空对象模式。

    1. 责任链(Chain Of Responsibility)

    Intent

    使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

    Class Diagram

    • Handler:定义处理请求的接口,并且实现后继链(successor)

    Implementation

     1 public abstract class Handler {
     2 
     3     protected Handler successor;
     4 
     5 
     6     public Handler(Handler successor) {
     7         this.successor = successor;
     8     }
     9 
    10 
    11     protected abstract void handleRequest(Request request);
    12 }
    View Code
     1 public class ConcreteHandler1 extends Handler {
     2 
     3     public ConcreteHandler1(Handler successor) {
     4         super(successor);
     5     }
     6 
     7 
     8     @Override
     9     protected void handleRequest(Request request) {
    10         if (request.getType() == RequestType.TYPE1) {
    11             System.out.println(request.getName() + " is handle by ConcreteHandler1");
    12             return;
    13         }
    14         if (successor != null) {
    15             successor.handleRequest(request);
    16         }
    17     }
    18 }
    View Code
     1 public class ConcreteHandler2 extends Handler {
     2 
     3     public ConcreteHandler2(Handler successor) {
     4         super(successor);
     5     }
     6 
     7 
     8     @Override
     9     protected void handleRequest(Request request) {
    10         if (request.getType() == RequestType.TYPE2) {
    11             System.out.println(request.getName() + " is handle by ConcreteHandler2");
    12             return;
    13         }
    14         if (successor != null) {
    15             successor.handleRequest(request);
    16         }
    17     }
    18 }
    View Code
     1 public class Request {
     2 
     3     private RequestType type;
     4     private String name;
     5 
     6 
     7     public Request(RequestType type, String name) {
     8         this.type = type;
     9         this.name = name;
    10     }
    11 
    12 
    13     public RequestType getType() {
    14         return type;
    15     }
    16 
    17 
    18     public String getName() {
    19         return name;
    20     }
    21 }
    View Code
    1 public enum RequestType {
    2     TYPE1, TYPE2
    3 }
     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4 
     5         Handler handler1 = new ConcreteHandler1(null);
     6         Handler handler2 = new ConcreteHandler2(handler1);
     7 
     8         Request request1 = new Request(RequestType.TYPE1, "request1");
     9         handler2.handleRequest(request1);
    10 
    11         Request request2 = new Request(RequestType.TYPE2, "request2");
    12         handler2.handleRequest(request2);
    13     }
    14 }
    View Code
    1 输出:
    2 request1 is handle by ConcreteHandler1
    3 request2 is handle by ConcreteHandler2

    2. 命令(Command)

    Intent

    将命令封装成对象中,具有以下作用:

    • 使用命令来参数化其它对象
    • 将命令放入队列中进行排队
    • 将命令的操作记录到日志中
    • 支持可撤销的操作

    Class Diagram

    • Command:命令
    • Receiver:命令接收者,也就是命令真正的执行者
    • Invoker:通过它来调用命令
    • Client:可以设置命令与命令的接收者

    Implementation

    设计一个遥控器,可以控制电灯开关。

    1 public interface Command {
    2     void execute();
    3 }
     1 public class LightOnCommand implements Command {
     2     Light light;
     3 
     4     public LightOnCommand(Light light) {
     5         this.light = light;
     6     }
     7 
     8     @Override
     9     public void execute() {
    10         light.on();
    11     }
    12 }
    View Code
     1 public class LightOffCommand implements Command {
     2     Light light;
     3 
     4     public LightOffCommand(Light light) {
     5         this.light = light;
     6     }
     7 
     8     @Override
     9     public void execute() {
    10         light.off();
    11     }
    12 }
    View Code
     1 public class Light {
     2 
     3     public void on() {
     4         System.out.println("Light is on!");
     5     }
     6 
     7     public void off() {
     8         System.out.println("Light is off!");
     9     }
    10 }
    View Code
     1 /**
     2  * 遥控器
     3  */
     4 public class Invoker {
     5     private Command[] onCommands;
     6     private Command[] offCommands;
     7     private final int slotNum = 7;
     8 
     9     public Invoker() {
    10         this.onCommands = new Command[slotNum];
    11         this.offCommands = new Command[slotNum];
    12     }
    13 
    14     public void setOnCommand(Command command, int slot) {
    15         onCommands[slot] = command;
    16     }
    17 
    18     public void setOffCommand(Command command, int slot) {
    19         offCommands[slot] = command;
    20     }
    21 
    22     public void onButtonWasPushed(int slot) {
    23         onCommands[slot].execute();
    24     }
    25 
    26     public void offButtonWasPushed(int slot) {
    27         offCommands[slot].execute();
    28     }
    29 }
    View Code
     1 public class Client {
     2     public static void main(String[] args) {
     3         Invoker invoker = new Invoker();
     4         Light light = new Light();
     5         Command lightOnCommand = new LightOnCommand(light);
     6         Command lightOffCommand = new LightOffCommand(light);
     7         invoker.setOnCommand(lightOnCommand, 0);
     8         invoker.setOffCommand(lightOffCommand, 0);
     9         invoker.onButtonWasPushed(0);
    10         invoker.offButtonWasPushed(0);
    11     }
    12 }

    3. 解释器(Interpreter)

    Intent

    为语言创建解释器,通常由语言的语法和语法分析来定义。

    Class Diagram

    • TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。
    • Context:上下文,包含解释器之外的一些全局信息。

    Implementation

    以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。

    例如一颗解析树为 D And (A Or (B C)),文本 "D A" 满足该解析树定义的规则。

    这里的 Context 指的是 String。

    1 public abstract class Expression {
    2     public abstract boolean interpret(String str);
    3 }
     1 public class TerminalExpression extends Expression {
     2 
     3     private String literal = null;
     4 
     5     public TerminalExpression(String str) {
     6         literal = str;
     7     }
     8 
     9     public boolean interpret(String str) {
    10         StringTokenizer st = new StringTokenizer(str);
    11         while (st.hasMoreTokens()) {
    12             String test = st.nextToken();
    13             if (test.equals(literal)) {
    14                 return true;
    15             }
    16         }
    17         return false;
    18     }
    19 }
    View Code
     1 public class AndExpression extends Expression {
     2 
     3     private Expression expression1 = null;
     4     private Expression expression2 = null;
     5 
     6     public AndExpression(Expression expression1, Expression expression2) {
     7         this.expression1 = expression1;
     8         this.expression2 = expression2;
     9     }
    10 
    11     public boolean interpret(String str) {
    12         return expression1.interpret(str) && expression2.interpret(str);
    13     }
    14 }
    View Code
     1 public class OrExpression extends Expression {
     2     private Expression expression1 = null;
     3     private Expression expression2 = null;
     4 
     5     public OrExpression(Expression expression1, Expression expression2) {
     6         this.expression1 = expression1;
     7         this.expression2 = expression2;
     8     }
     9 
    10     public boolean interpret(String str) {
    11         return expression1.interpret(str) || expression2.interpret(str);
    12     }
    13 }
    View Code
     1 public class Client {
     2 
     3     /**
     4      * 构建解析树
     5      */
     6     public static Expression buildInterpreterTree() {
     7         // Literal
     8         Expression terminal1 = new TerminalExpression("A");
     9         Expression terminal2 = new TerminalExpression("B");
    10         Expression terminal3 = new TerminalExpression("C");
    11         Expression terminal4 = new TerminalExpression("D");
    12         // B C
    13         Expression alternation1 = new OrExpression(terminal2, terminal3);
    14         // A Or (B C)
    15         Expression alternation2 = new OrExpression(terminal1, alternation1);
    16         // D And (A Or (B C))
    17         return new AndExpression(terminal4, alternation2);
    18     }
    19 
    20     public static void main(String[] args) {
    21         Expression define = buildInterpreterTree();
    22         String context1 = "D A";
    23         String context2 = "A B";
    24         System.out.println(define.interpret(context1));  // true
    25         System.out.println(define.interpret(context2));  // false
    26     }
    27 }
    View Code

    4. 迭代器(Iterator)

    Intent

    提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

    Class Diagram

    • Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
    • Iterator 主要定义了 hasNext() 和 next() 方法;
    • Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。

    Implementation

    1 public interface Aggregate {
    2     Iterator createIterator();
    3 }
     1 public class ConcreteAggregate implements Aggregate {
     2 
     3     private Integer[] items;
     4 
     5     public ConcreteAggregate() {
     6         items = new Integer[10];
     7         for (int i = 0; i < items.length; i++) {
     8             items[i] = i;
     9         }
    10     }
    11 
    12     @Override
    13     public Iterator createIterator() {
    14         return new ConcreteIterator<Integer>(items);
    15     }
    16 }
    View Code
    1 public interface Iterator<Item> {
    2     Item next();
    3     boolean hasNext();
    4 }
     1 public class ConcreteIterator<Item> implements Iterator {
     2 
     3     private Item[] items;
     4     private int position = 0;
     5 
     6     public ConcreteIterator(Item[] items) {
     7         this.items = items;
     8     }
     9 
    10     @Override
    11     public Object next() {
    12         return items[position++];
    13     }
    14 
    15     @Override
    16     public boolean hasNext() {
    17         return position < items.length;
    18     }
    19 }
    View Code
    1 public class Client {
    2     public static void main(String[] args) {
    3         Aggregate aggregate = new ConcreteAggregate();
    4         Iterator<Integer> iterator = aggregate.createIterator();
    5         while (iterator.hasNext()) {
    6             System.out.println(iterator.next());
    7         }
    8     }
    9 }

    5. 中介者(Mediator)

    Intent

    集中相关对象之间复杂的沟通和控制方式。

    Class Diagram

    • Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
    • Colleague:同事,相关对象。

    Implementation

    Alarm(闹钟)、CoffeePot(咖啡壶)、Calendar(日历)、Sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:

    使用中介者模式可以将复杂的依赖结构变成星形结构:

    1 public abstract class Colleague {
    2     public abstract void onEvent(Mediator mediator);
    3 }
     1 public class Alarm extends Colleague {
     2 
     3     @Override
     4     public void onEvent(Mediator mediator) {
     5         mediator.doEvent("alarm");
     6     }
     7 
     8     public void doAlarm() {
     9         System.out.println("doAlarm()");
    10     }
    11 }
    View Code
     1 public class CoffeePot extends Colleague {
     2     @Override
     3     public void onEvent(Mediator mediator) {
     4         mediator.doEvent("coffeePot");
     5     }
     6 
     7     public void doCoffeePot() {
     8         System.out.println("doCoffeePot()");
     9     }
    10 }
    View Code
     1 public class Calender extends Colleague {
     2     @Override
     3     public void onEvent(Mediator mediator) {
     4         mediator.doEvent("calender");
     5     }
     6 
     7     public void doCalender() {
     8         System.out.println("doCalender()");
     9     }
    10 }
    View Code
     1 public class Sprinkler extends Colleague {
     2     @Override
     3     public void onEvent(Mediator mediator) {
     4         mediator.doEvent("sprinkler");
     5     }
     6 
     7     public void doSprinkler() {
     8         System.out.println("doSprinkler()");
     9     }
    10 }
    View Code
    1 public abstract class Mediator {
    2     public abstract void doEvent(String eventType);
    3 }
     1 public class ConcreteMediator extends Mediator {
     2     private Alarm alarm;
     3     private CoffeePot coffeePot;
     4     private Calender calender;
     5     private Sprinkler sprinkler;
     6 
     7     public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calender calender, Sprinkler sprinkler) {
     8         this.alarm = alarm;
     9         this.coffeePot = coffeePot;
    10         this.calender = calender;
    11         this.sprinkler = sprinkler;
    12     }
    13 
    14     @Override
    15     public void doEvent(String eventType) {
    16         switch (eventType) {
    17             case "alarm":
    18                 doAlarmEvent();
    19                 break;
    20             case "coffeePot":
    21                 doCoffeePotEvent();
    22                 break;
    23             case "calender":
    24                 doCalenderEvent();
    25                 break;
    26             default:
    27                 doSprinklerEvent();
    28         }
    29     }
    30 
    31     public void doAlarmEvent() {
    32         alarm.doAlarm();
    33         coffeePot.doCoffeePot();
    34         calender.doCalender();
    35         sprinkler.doSprinkler();
    36     }
    37 
    38     public void doCoffeePotEvent() {
    39         // ...
    40     }
    41 
    42     public void doCalenderEvent() {
    43         // ...
    44     }
    45 
    46     public void doSprinklerEvent() {
    47         // ...
    48     }
    49 }
    View Code
     1 public class Client {
     2     public static void main(String[] args) {
     3         Alarm alarm = new Alarm();
     4         CoffeePot coffeePot = new CoffeePot();
     5         Calender calender = new Calender();
     6         Sprinkler sprinkler = new Sprinkler();
     7         Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
     8         // 闹钟事件到达,调用中介者就可以操作相关对象
     9         alarm.onEvent(mediator);
    10     }
    11 }
    1 输出:
    2 doAlarm()
    3 doCoffeePot()
    4 doCalender()
    5 doSprinkler()

    6. 备忘录(Memento)

    Intent

    在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。

    Class Diagram

    • Originator:原始对象
    • Caretaker:负责保存好备忘录
    • Memento:备忘录,存储原始对象的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。

    Implementation

    以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。

     1 /**
     2  * Originator Interface
     3  */
     4 public interface Calculator {
     5 
     6     // Create Memento
     7     PreviousCalculationToCareTaker backupLastCalculation();
     8 
     9     // setMemento
    10     void restorePreviousCalculation(PreviousCalculationToCareTaker memento);
    11 
    12     int getCalculationResult();
    13 
    14     void setFirstNumber(int firstNumber);
    15 
    16     void setSecondNumber(int secondNumber);
    17 }
    View Code
     1 /**
     2  * Originator Implementation
     3  */
     4 public class CalculatorImp implements Calculator {
     5 
     6     private int firstNumber;
     7     private int secondNumber;
     8 
     9     @Override
    10     public PreviousCalculationToCareTaker backupLastCalculation() {
    11         // create a memento object used for restoring two numbers
    12         return new PreviousCalculationImp(firstNumber, secondNumber);
    13     }
    14 
    15     @Override
    16     public void restorePreviousCalculation(PreviousCalculationToCareTaker memento) {
    17         this.firstNumber = ((PreviousCalculationToOriginator) memento).getFirstNumber();
    18         this.secondNumber = ((PreviousCalculationToOriginator) memento).getSecondNumber();
    19     }
    20 
    21     @Override
    22     public int getCalculationResult() {
    23         // result is adding two numbers
    24         return firstNumber + secondNumber;
    25     }
    26 
    27     @Override
    28     public void setFirstNumber(int firstNumber) {
    29         this.firstNumber = firstNumber;
    30     }
    31 
    32     @Override
    33     public void setSecondNumber(int secondNumber) {
    34         this.secondNumber = secondNumber;
    35     }
    36 }
    View Code
    1 /**
    2  * Memento Interface to Originator
    3  *
    4  * This interface allows the originator to restore its state
    5  */
    6 public interface PreviousCalculationToOriginator {
    7     int getFirstNumber();
    8     int getSecondNumber();
    9 }
    1 /**
    2  *  Memento interface to CalculatorOperator (Caretaker)
    3  */
    4 public interface PreviousCalculationToCareTaker {
    5     // no operations permitted for the caretaker
    6 }
     1 /**
     2  * Memento Object Implementation
     3  * <p>
     4  * Note that this object implements both interfaces to Originator and CareTaker
     5  */
     6 public class PreviousCalculationImp implements PreviousCalculationToCareTaker,
     7         PreviousCalculationToOriginator {
     8 
     9     private int firstNumber;
    10     private int secondNumber;
    11 
    12     public PreviousCalculationImp(int firstNumber, int secondNumber) {
    13         this.firstNumber = firstNumber;
    14         this.secondNumber = secondNumber;
    15     }
    16 
    17     @Override
    18     public int getFirstNumber() {
    19         return firstNumber;
    20     }
    21 
    22     @Override
    23     public int getSecondNumber() {
    24         return secondNumber;
    25     }
    26 }
    View Code
     1 /**
     2  * CareTaker object
     3  */
     4 public class Client {
     5 
     6     public static void main(String[] args) {
     7         // program starts
     8         Calculator calculator = new CalculatorImp();
     9 
    10         // assume user enters two numbers
    11         calculator.setFirstNumber(10);
    12         calculator.setSecondNumber(100);
    13 
    14         // find result
    15         System.out.println(calculator.getCalculationResult());
    16 
    17         // Store result of this calculation in case of error
    18         PreviousCalculationToCareTaker memento = calculator.backupLastCalculation();
    19 
    20         // user enters a number
    21         calculator.setFirstNumber(17);
    22 
    23         // user enters a wrong second number and calculates result
    24         calculator.setSecondNumber(-290);
    25 
    26         // calculate result
    27         System.out.println(calculator.getCalculationResult());
    28 
    29         // user hits CTRL + Z to undo last operation and see last result
    30         calculator.restorePreviousCalculation(memento);
    31 
    32         // result restored
    33         System.out.println(calculator.getCalculationResult());
    34     }
    35 }
    View Code
    1 输出:
    2 110
    3 -273
    4 110

    7. 观察者(Observer)

    Intent

    定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

    主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

    Class Diagram

    主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。

    观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。

    Implementation

    天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。

    1 public interface Subject {
    2     void registerObserver(Observer o);
    3 
    4     void removeObserver(Observer o);
    5 
    6     void notifyObserver();
    7 }
     1 public class WeatherData implements Subject {
     2     private List<Observer> observers;
     3     private float temperature;
     4     private float humidity;
     5     private float pressure;
     6 
     7     public WeatherData() {
     8         observers = new ArrayList<>();
     9     }
    10 
    11     public void setMeasurements(float temperature, float humidity, float pressure) {
    12         this.temperature = temperature;
    13         this.humidity = humidity;
    14         this.pressure = pressure;
    15         notifyObserver();
    16     }
    17 
    18     @Override
    19     public void registerObserver(Observer o) {
    20         observers.add(o);
    21     }
    22 
    23     @Override
    24     public void removeObserver(Observer o) {
    25         int i = observers.indexOf(o);
    26         if (i >= 0) {
    27             observers.remove(i);
    28         }
    29     }
    30 
    31     @Override
    32     public void notifyObserver() {
    33         for (Observer o : observers) {
    34             o.update(temperature, humidity, pressure);
    35         }
    36     }
    37 }
    View Code
    1 public interface Observer {
    2     void update(float temp, float humidity, float pressure);
    3 }
     1 public class StatisticsDisplay implements Observer {
     2 
     3     public StatisticsDisplay(Subject weatherData) {
     4         weatherData.registerObserver(this);
     5     }
     6 
     7     @Override
     8     public void update(float temp, float humidity, float pressure) {
     9         System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
    10     }
    11 }
    View Code
     1 public class CurrentConditionsDisplay implements Observer {
     2 
     3     public CurrentConditionsDisplay(Subject weatherData) {
     4         weatherData.registerObserver(this);
     5     }
     6 
     7     @Override
     8     public void update(float temp, float humidity, float pressure) {
     9         System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
    10     }
    11 }
    View Code
     1 public class WeatherStation {
     2     public static void main(String[] args) {
     3         WeatherData weatherData = new WeatherData();
     4         CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
     5         StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
     6 
     7         weatherData.setMeasurements(0, 0, 0);
     8         weatherData.setMeasurements(1, 1, 1);
     9     }
    10 }
    1 输出:
    2 CurrentConditionsDisplay.update: 0.0 0.0 0.0
    3 StatisticsDisplay.update: 0.0 0.0 0.0
    4 CurrentConditionsDisplay.update: 1.0 1.0 1.0
    5 StatisticsDisplay.update: 1.0 1.0 1.0

    8. 状态(State)

    Intent

    允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。

    Class Diagram

    Implementation

    糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。

     1 public interface State {
     2     /**
     3      * 投入 25 分钱
     4      */
     5     void insertQuarter();
     6 
     7     /**
     8      * 退回 25 分钱
     9      */
    10     void ejectQuarter();
    11 
    12     /**
    13      * 转动曲柄
    14      */
    15     void turnCrank();
    16 
    17     /**
    18      * 发放糖果
    19      */
    20     void dispense();
    21 }
     1 public class HasQuarterState implements State {
     2 
     3     private GumballMachine gumballMachine;
     4 
     5     public HasQuarterState(GumballMachine gumballMachine) {
     6         this.gumballMachine = gumballMachine;
     7     }
     8 
     9     @Override
    10     public void insertQuarter() {
    11         System.out.println("You can't insert another quarter");
    12     }
    13 
    14     @Override
    15     public void ejectQuarter() {
    16         System.out.println("Quarter returned");
    17         gumballMachine.setState(gumballMachine.getNoQuarterState());
    18     }
    19 
    20     @Override
    21     public void turnCrank() {
    22         System.out.println("You turned...");
    23         gumballMachine.setState(gumballMachine.getSoldState());
    24     }
    25 
    26     @Override
    27     public void dispense() {
    28         System.out.println("No gumball dispensed");
    29     }
    30 }
    View Code
     1 public class NoQuarterState implements State {
     2 
     3     GumballMachine gumballMachine;
     4 
     5     public NoQuarterState(GumballMachine gumballMachine) {
     6         this.gumballMachine = gumballMachine;
     7     }
     8 
     9     @Override
    10     public void insertQuarter() {
    11         System.out.println("You insert a quarter");
    12         gumballMachine.setState(gumballMachine.getHasQuarterState());
    13     }
    14 
    15     @Override
    16     public void ejectQuarter() {
    17         System.out.println("You haven't insert a quarter");
    18     }
    19 
    20     @Override
    21     public void turnCrank() {
    22         System.out.println("You turned, but there's no quarter");
    23     }
    24 
    25     @Override
    26     public void dispense() {
    27         System.out.println("You need to pay first");
    28     }
    29 }
    View Code
     1 public class SoldOutState implements State {
     2 
     3     GumballMachine gumballMachine;
     4 
     5     public SoldOutState(GumballMachine gumballMachine) {
     6         this.gumballMachine = gumballMachine;
     7     }
     8 
     9     @Override
    10     public void insertQuarter() {
    11         System.out.println("You can't insert a quarter, the machine is sold out");
    12     }
    13 
    14     @Override
    15     public void ejectQuarter() {
    16         System.out.println("You can't eject, you haven't inserted a quarter yet");
    17     }
    18 
    19     @Override
    20     public void turnCrank() {
    21         System.out.println("You turned, but there are no gumballs");
    22     }
    23 
    24     @Override
    25     public void dispense() {
    26         System.out.println("No gumball dispensed");
    27     }
    28 }
    View Code
     1 public class SoldState implements State {
     2 
     3     GumballMachine gumballMachine;
     4 
     5     public SoldState(GumballMachine gumballMachine) {
     6         this.gumballMachine = gumballMachine;
     7     }
     8 
     9     @Override
    10     public void insertQuarter() {
    11         System.out.println("Please wait, we're already giving you a gumball");
    12     }
    13 
    14     @Override
    15     public void ejectQuarter() {
    16         System.out.println("Sorry, you already turned the crank");
    17     }
    18 
    19     @Override
    20     public void turnCrank() {
    21         System.out.println("Turning twice doesn't get you another gumball!");
    22     }
    23 
    24     @Override
    25     public void dispense() {
    26         gumballMachine.releaseBall();
    27         if (gumballMachine.getCount() > 0) {
    28             gumballMachine.setState(gumballMachine.getNoQuarterState());
    29         } else {
    30             System.out.println("Oops, out of gumballs");
    31             gumballMachine.setState(gumballMachine.getSoldOutState());
    32         }
    33     }
    34 }
    View Code
     1 public class GumballMachine {
     2 
     3     private State soldOutState;
     4     private State noQuarterState;
     5     private State hasQuarterState;
     6     private State soldState;
     7 
     8     private State state;
     9     private int count = 0;
    10 
    11     public GumballMachine(int numberGumballs) {
    12         count = numberGumballs;
    13         soldOutState = new SoldOutState(this);
    14         noQuarterState = new NoQuarterState(this);
    15         hasQuarterState = new HasQuarterState(this);
    16         soldState = new SoldState(this);
    17 
    18         if (numberGumballs > 0) {
    19             state = noQuarterState;
    20         } else {
    21             state = soldOutState;
    22         }
    23     }
    24 
    25     public void insertQuarter() {
    26         state.insertQuarter();
    27     }
    28 
    29     public void ejectQuarter() {
    30         state.ejectQuarter();
    31     }
    32 
    33     public void turnCrank() {
    34         state.turnCrank();
    35         state.dispense();
    36     }
    37 
    38     public void setState(State state) {
    39         this.state = state;
    40     }
    41 
    42     public void releaseBall() {
    43         System.out.println("A gumball comes rolling out the slot...");
    44         if (count != 0) {
    45             count -= 1;
    46         }
    47     }
    48 
    49     public State getSoldOutState() {
    50         return soldOutState;
    51     }
    52 
    53     public State getNoQuarterState() {
    54         return noQuarterState;
    55     }
    56 
    57     public State getHasQuarterState() {
    58         return hasQuarterState;
    59     }
    60 
    61     public State getSoldState() {
    62         return soldState;
    63     }
    64 
    65     public int getCount() {
    66         return count;
    67     }
    68 }
    View Code
     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         GumballMachine gumballMachine = new GumballMachine(5);
     5 
     6         gumballMachine.insertQuarter();
     7         gumballMachine.turnCrank();
     8 
     9         gumballMachine.insertQuarter();
    10         gumballMachine.ejectQuarter();
    11         gumballMachine.turnCrank();
    12 
    13         gumballMachine.insertQuarter();
    14         gumballMachine.turnCrank();
    15         gumballMachine.insertQuarter();
    16         gumballMachine.turnCrank();
    17         gumballMachine.ejectQuarter();
    18 
    19         gumballMachine.insertQuarter();
    20         gumballMachine.insertQuarter();
    21         gumballMachine.turnCrank();
    22         gumballMachine.insertQuarter();
    23         gumballMachine.turnCrank();
    24         gumballMachine.insertQuarter();
    25         gumballMachine.turnCrank();
    26     }
    27 }
    View Code
     1 输出:
     2 You insert a quarter
     3 You turned...
     4 A gumball comes rolling out the slot...
     5 You insert a quarter
     6 Quarter returned
     7 You turned, but there's no quarter
     8 You need to pay first
     9 You insert a quarter
    10 You turned...
    11 A gumball comes rolling out the slot...
    12 You insert a quarter
    13 You turned...
    14 A gumball comes rolling out the slot...
    15 You haven't insert a quarter
    16 You insert a quarter
    17 You can't insert another quarter
    18 You turned...
    19 A gumball comes rolling out the slot...
    20 You insert a quarter
    21 You turned...
    22 A gumball comes rolling out the slot...
    23 Oops, out of gumballs
    24 You can't insert a quarter, the machine is sold out
    25 You turned, but there are no gumballs
    26 No gumball dispensed

    9. 策略(Strategy)

    Intent

    定义一系列算法,封装每个算法,并使它们可以互换。

    策略模式可以让算法独立于使用它的客户端。

    Class Diagram

    • Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
    • Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。

    与状态模式的比较

    状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。

    状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。

    Implementation

    设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。

    1 public interface QuackBehavior {
    2     void quack();
    3 }
    1 public class Quack implements QuackBehavior {
    2     @Override
    3     public void quack() {
    4         System.out.println("quack!");
    5     }
    6 }
    1 public class Squeak implements QuackBehavior{
    2     @Override
    3     public void quack() {
    4         System.out.println("squeak!");
    5     }
    6 }
     1 public class Duck {
     2 
     3     private QuackBehavior quackBehavior;
     4 
     5     public void performQuack() {
     6         if (quackBehavior != null) {
     7             quackBehavior.quack();
     8         }
     9     }
    10 
    11     public void setQuackBehavior(QuackBehavior quackBehavior) {
    12         this.quackBehavior = quackBehavior;
    13     }
    14 }
    View Code
     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         Duck duck = new Duck();
     5         duck.setQuackBehavior(new Squeak());
     6         duck.performQuack();
     7         duck.setQuackBehavior(new Quack());
     8         duck.performQuack();
     9     }
    10 }
    1 输出:
    2 squeak!
    3 quack!

    10. 模板方法(Template Method)

    Intent

    定义算法框架,并将一些步骤的实现延迟到子类。

    通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

    Class Diagram

    Implementation

    冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。

     1 public abstract class CaffeineBeverage {
     2 
     3     final void prepareRecipe() {
     4         boilWater();
     5         brew();
     6         pourInCup();
     7         addCondiments();
     8     }
     9 
    10     abstract void brew();
    11 
    12     abstract void addCondiments();
    13 
    14     void boilWater() {
    15         System.out.println("boilWater");
    16     }
    17 
    18     void pourInCup() {
    19         System.out.println("pourInCup");
    20     }
    21 }
     1 public class Coffee extends CaffeineBeverage {
     2     @Override
     3     void brew() {
     4         System.out.println("Coffee.brew");
     5     }
     6 
     7     @Override
     8     void addCondiments() {
     9         System.out.println("Coffee.addCondiments");
    10     }
    11 }
     1 public class Tea extends CaffeineBeverage {
     2     @Override
     3     void brew() {
     4         System.out.println("Tea.brew");
     5     }
     6 
     7     @Override
     8     void addCondiments() {
     9         System.out.println("Tea.addCondiments");
    10     }
    11 }
    1 public class Client {
    2     public static void main(String[] args) {
    3         CaffeineBeverage caffeineBeverage = new Coffee();
    4         caffeineBeverage.prepareRecipe();
    5         System.out.println("-----------");
    6         caffeineBeverage = new Tea();
    7         caffeineBeverage.prepareRecipe();
    8     }
    9 }
     1 输出:
     2 boilWater
     3 Coffee.brew
     4 pourInCup
     5 Coffee.addCondiments
     6 -----------
     7 boilWater
     8 Tea.brew
     9 pourInCup
    10 Tea.addCondiments

    11. 访问者(Visitor)

    Intent

    为一个对象结构(比如组合结构)增加新能力。

    Class Diagram

    • Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
    • ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
    • ObjectStructure:对象结构,可以是组合结构,或者是一个集合。

    Implementation

    1 public interface Element {
    2     void accept(Visitor visitor);
    3 }
     1 class CustomerGroup {
     2 
     3     private List<Customer> customers = new ArrayList<>();
     4 
     5     void accept(Visitor visitor) {
     6         for (Customer customer : customers) {
     7             customer.accept(visitor);
     8         }
     9     }
    10 
    11     void addCustomer(Customer customer) {
    12         customers.add(customer);
    13     }
    14 }
    View Code
     1 public class Customer implements Element {
     2 
     3     private String name;
     4     private List<Order> orders = new ArrayList<>();
     5 
     6     Customer(String name) {
     7         this.name = name;
     8     }
     9 
    10     String getName() {
    11         return name;
    12     }
    13 
    14     void addOrder(Order order) {
    15         orders.add(order);
    16     }
    17 
    18     public void accept(Visitor visitor) {
    19         visitor.visit(this);
    20         for (Order order : orders) {
    21             order.accept(visitor);
    22         }
    23     }
    24 }
    View Code
     1 public class Order implements Element {
     2 
     3     private String name;
     4     private List<Item> items = new ArrayList();
     5 
     6     Order(String name) {
     7         this.name = name;
     8     }
     9 
    10     Order(String name, String itemName) {
    11         this.name = name;
    12         this.addItem(new Item(itemName));
    13     }
    14 
    15     String getName() {
    16         return name;
    17     }
    18 
    19     void addItem(Item item) {
    20         items.add(item);
    21     }
    22 
    23     public void accept(Visitor visitor) {
    24         visitor.visit(this);
    25 
    26         for (Item item : items) {
    27             item.accept(visitor);
    28         }
    29     }
    30 }
    View Code
     1 public class Item implements Element {
     2 
     3     private String name;
     4 
     5     Item(String name) {
     6         this.name = name;
     7     }
     8 
     9     String getName() {
    10         return name;
    11     }
    12 
    13     public void accept(Visitor visitor) {
    14         visitor.visit(this);
    15     }
    16 }
    View Code
    1 public interface Visitor {
    2     void visit(Customer customer);
    3 
    4     void visit(Order order);
    5 
    6     void visit(Item item);
    7 }
     1 public class GeneralReport implements Visitor {
     2 
     3     private int customersNo;
     4     private int ordersNo;
     5     private int itemsNo;
     6 
     7     public void visit(Customer customer) {
     8         System.out.println(customer.getName());
     9         customersNo++;
    10     }
    11 
    12     public void visit(Order order) {
    13         System.out.println(order.getName());
    14         ordersNo++;
    15     }
    16 
    17     public void visit(Item item) {
    18         System.out.println(item.getName());
    19         itemsNo++;
    20     }
    21 
    22     public void displayResults() {
    23         System.out.println("Number of customers: " + customersNo);
    24         System.out.println("Number of orders:    " + ordersNo);
    25         System.out.println("Number of items:     " + itemsNo);
    26     }
    27 }
    View Code
     1 public class Client {
     2     public static void main(String[] args) {
     3         Customer customer1 = new Customer("customer1");
     4         customer1.addOrder(new Order("order1", "item1"));
     5         customer1.addOrder(new Order("order2", "item1"));
     6         customer1.addOrder(new Order("order3", "item1"));
     7 
     8         Order order = new Order("order_a");
     9         order.addItem(new Item("item_a1"));
    10         order.addItem(new Item("item_a2"));
    11         order.addItem(new Item("item_a3"));
    12         Customer customer2 = new Customer("customer2");
    13         customer2.addOrder(order);
    14 
    15         CustomerGroup customers = new CustomerGroup();
    16         customers.addCustomer(customer1);
    17         customers.addCustomer(customer2);
    18 
    19         GeneralReport visitor = new GeneralReport();
    20         customers.accept(visitor);
    21         visitor.displayResults();
    22     }
    23 }
    View Code
     1 输出:
     2 customer1
     3 order1
     4 item1
     5 order2
     6 item1
     7 order3
     8 item1
     9 customer2
    10 order_a
    11 item_a1
    12 item_a2
    13 item_a3
    14 Number of customers: 2
    15 Number of orders:    4
    16 Number of items:     6

    12. 空对象(Null)

    Intent

    使用什么都不做的空对象来代替 NULL。

    一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。

    Class Diagram

    Implementation

    1 public abstract class AbstractOperation {
    2     abstract void request();
    3 }
    1 public class RealOperation extends AbstractOperation {
    2     @Override
    3     void request() {
    4         System.out.println("do something");
    5     }
    6 }
    1 public class NullOperation extends AbstractOperation{
    2     @Override
    3     void request() {
    4         // do nothing
    5     }
    6 }
     1 public class Client {
     2     public static void main(String[] args) {
     3         AbstractOperation abstractOperation = func(-1);
     4         abstractOperation.request();
     5     }
     6 
     7     public static AbstractOperation func(int para) {
     8         if (para < 0) {
     9             return new NullOperation();
    10         }
    11         return new RealOperation();
    12     }
    13 }
    View Code

     

     

    日暮乡关何处是?

            烟波江上使人愁

     

  • 相关阅读:
    css切图Sprites
    javascript改变position值实现菜单滚动至顶部后固定
    Cannot create type class java.io.File from value
    关于如何拍摄瓷器(转)
    Struts2的jar问题
    vim的基本操作
    Flask基础
    Flask入门
    MongoDB 之 数据类型
    基于DBUtils实现数据库连接池
  • 原文地址:https://www.cnblogs.com/taojietaoge/p/15048275.html
Copyright © 2011-2022 走看看