Java 23种设计模式 - 行为型模式11种

Java 23种设计模式 - 行为型模式11种

1 策略模式 Strategy Pattern

一个类的行为或其算法可以在运行时更改

优点:

  1. 算法可以自由切换。
  2. 避免使用多重条件判断。
  3. 扩展性良好。

缺点:

  1. 策略类会增多。
  2. 所有策略类都需要对外暴露。

Java 数组的工具类 Arrays 中的排序方法是典型的应用了策略模式的例示。

按照给定的策略执行(Comparator)对数组进行排序。sort 方法是要做的事情,T[] a 数组是策略作用的对象,Comparator策略本身。其中 Comparator 是一个泛型接口,所有实现了策略接口的具体策略都可以作为参数传入。Comparator 使用通配符,允许利用 T 的超类的策略对 T 进行操作。

java 复制代码
public static <T> void sort(T[] a, Comparator<? super T> c){
    //...
}

1.1 例子

  • Strategy 策略接口
  • OperationAdd 加法
  • OperationSubstract 减法
  • OperationMultiply 乘法
java 复制代码
public interface Strategy {
   public int doOperation(int num1, int num2);
}
java 复制代码
public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}
java 复制代码
public class OperationSubstract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}
java 复制代码
public class OperationMultiply implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}
java 复制代码
public class Context {
   private Strategy strategy;
 
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
 
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

client

java 复制代码
public class Client {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());    
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationSubstract());      
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationMultiply());    
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}

result:

复制代码
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

2 模板模式 Template Pattern

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。通俗的说的就是有很多相同的步骤的,在某一些地方可能有一些差别适合于这种模式,

准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现

比如大话设计模式中说到的考试场景中,每个人的试卷都是一样的,只有答案不一样。这种场景就适合于模板方法模式。

2.1 例子

  • Game 游戏
  • Cricket 板球
  • Football 足球
java 复制代码
public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();
 
   //模板
   public final void play(){
 
      //初始化游戏
      initialize();
 
      //开始游戏
      startPlay();
 
      //结束游戏
      endPlay();
   }
}
java 复制代码
public class Cricket extends Game {
 
   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }
 
   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }
 
   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}
java 复制代码
public class Football extends Game {
 
   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }
 
   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }
 
   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

client

java 复制代码
public class TemplatePatternDemo {
   public static void main(String[] args) {
 
      Game game = new Cricket();
      game.play();
      System.out.println();
      game = new Football();
      game.play();      
   }
}

result

复制代码
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!

Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!

3 观察者模式 Observer Pattern

对象间存在一对多关系依赖,当一个对象被修改时,则会自动通知它的依赖对象。

3.1 例子

  • Subject 被观察者(主题)
  • Observer 观察者
  • BinaryObserver 具体的观察者
  • OctalObserver 具体的观察者
  • HexaObserver 具体的观察者
java 复制代码
import java.util.ArrayList;
import java.util.List;
 
public class Subject {
   
   private List<Observer> observers 
      = new ArrayList<Observer>();
   private int state;
 
   public int getState() {
      return state;
   }
 
   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }
 
   public void attach(Observer observer){
      observers.add(observer);      
   }
 
   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   }  
}
java 复制代码
public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}
java 复制代码
public class BinaryObserver extends Observer{
 
   public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }
 
   @Override
   public void update() {
      System.out.println( "Binary String: " 
      + Integer.toBinaryString( subject.getState() ) ); 
   }
}
java 复制代码
public class OctalObserver extends Observer{
 
   public OctalObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }
 
   @Override
   public void update() {
     System.out.println( "Octal String: " 
     + Integer.toOctalString( subject.getState() ) ); 
   }
}
java 复制代码
public class HexaObserver extends Observer{
 
   public HexaObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }
 
   @Override
   public void update() {
      System.out.println( "Hex String: " 
      + Integer.toHexString( subject.getState() ).toUpperCase() ); 
   }
}

client

java 复制代码
public class Client {
   public static void main(String[] args) {
      Subject subject = new Subject();
 
      new HexaObserver(subject);
      new OctalObserver(subject);
      new BinaryObserver(subject);
 
      System.out.println("First state change: 15");   
      subject.setState(15);
      System.out.println("Second state change: 10");  
      subject.setState(10);
   }
}

result

复制代码
First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010

4 迭代子模式 Iterator Pattern

迭代子模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。

比如ArrayList中就有迭代子模式的实现方式

java 复制代码
public class ArrayList<E> {
    private class Itr implements Iterator<E> {}
}

4.1 例子

  • Collection 是需要遍历的对象,即聚集对象
  • Iterator 是迭代器对象,用于对聚集对象进行遍历访问

4.2 外部类方式

java 复制代码
public interface Collection {  
      
    public Iterator iterator();  
      
    /*取得集合元素*/  
    public Object get(int i);  
      
    /*取得集合大小*/  
    public int size();  
} 
java 复制代码
public interface Iterator {  
    //前移  
    public Object previous();  
      
    //后移  
    public Object next();  
    public boolean hasNext();  
      
    //取得第一个元素  
    public Object first();  
}
java 复制代码
public class MyCollection implements Collection {  
  
    public String string[] = {"A","B","C","D","E"};  
    @Override  
    public Iterator iterator() {  
        return new MyIterator(this);  
    }  
  
    @Override  
    public Object get(int i) {  
        return string[i];  
    }  
  
    @Override  
    public int size() {  
        return string.length;  
    }  
}
java 复制代码
public class MyIterator implements Iterator {  
  
    private Collection collection;  
    private int pos = -1;  
      
    public MyIterator(Collection collection){  
        this.collection = collection;  
    }  
      
    @Override  
    public Object previous() {  
        if(pos > 0){  
            pos--;  
        }  
        return collection.get(pos);  
    }  
  
    @Override  
    public Object next() {  
        if(pos<collection.size()-1){  
            pos++;  
        }  
        return collection.get(pos);  
    }  
  
    @Override  
    public boolean hasNext() {  
        if(pos<collection.size()-1){  
            return true;  
        }else{  
            return false;  
        }  
    }  
  
    @Override  
    public Object first() {  
        pos = 0;  
        return collection.get(pos);  
    }  
  
}  

client

java 复制代码
public class Test {  
  
    public static void main(String[] args) {  
        Collection collection = new MyCollection();  
        Iterator it = collection.iterator();  
          
        while(it.hasNext()){  
            System.out.println(it.next());  
        }  
    }  
} 

result

复制代码
A B C D E

4.3 内部类方式

java 复制代码
public interface Iterator {
   public boolean hasNext();
   public Object next();
}
java 复制代码
public interface Container {
   public Iterator getIterator();
}
java 复制代码
public class NameRepository implements Container {
   public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
 
   @Override
   public Iterator getIterator() {
      return new NameIterator();
   }
 
   private class NameIterator implements Iterator {
 
      int index;
 
      @Override
      public boolean hasNext() {
         if(index < names.length){
            return true;
         }
         return false;
      }
 
      @Override
      public Object next() {
         if(this.hasNext()){
            return names[index++];
         }
         return null;
      }     
   }
}
java 复制代码
public class IteratorPatternDemo {
   
   public static void main(String[] args) {
      NameRepository namesRepository = new NameRepository();
 
      for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
         String name = (String)iter.next();
         System.out.println("Name : " + name);
      }  
   }
}
复制代码
Name : Robert
Name : John
Name : Julie
Name : Lora

5 责任链模式 Chain of Responsibility Pattern

在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链,并沿着这条链传递请求,直到链上的某一个对象决定处理此请求。

实例:

  1. JAVA WEB 中 Apache Tomcat 对 Encoding 的处理
  2. Struts2 的拦截器,jsp servlet 的 Filter。
  3. Shiro 中的Filter链路

5.1 例子

抽象类

  • AbstractLogger

链上的处理者

  • ConsoleLogger
  • ErrorLogger
  • FileLogger
java 复制代码
public abstract class AbstractLogger {
   public static int INFO = 1;
   public static int DEBUG = 2;
   public static int ERROR = 3;
 
   protected int level;
 
   //责任链中的下一个元素
   protected AbstractLogger nextLogger;
 
   public void setNextLogger(AbstractLogger nextLogger){
      this.nextLogger = nextLogger;
   }
 
   public void logMessage(int level, String message){
      if(this.level <= level){
         write(message);
      }
      if(nextLogger !=null){
         nextLogger.logMessage(level, message);
      }
   }
 
   abstract protected void write(String message);
   
}
java 复制代码
public class ConsoleLogger extends AbstractLogger {
 
   public ConsoleLogger(int level){
      this.level = level;
   }
 
   @Override
   protected void write(String message) {    
      System.out.println("Standard Console::Logger: " + message);
   }
}
java 复制代码
public class ErrorLogger extends AbstractLogger {
 
   public ErrorLogger(int level){
      this.level = level;
   }
 
   @Override
   protected void write(String message) {    
      System.out.println("Error Console::Logger: " + message);
   }
}
java 复制代码
public class FileLogger extends AbstractLogger {
 
   public FileLogger(int level){
      this.level = level;
   }
 
   @Override
   protected void write(String message) {    
      System.out.println("File::Logger: " + message);
   }
}

client

java 复制代码
public class Client {
   
   private static AbstractLogger getChainOfLoggers(){
 
      AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
      AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
      AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
 
      errorLogger.setNextLogger(fileLogger);
      fileLogger.setNextLogger(consoleLogger);
 
      return errorLogger;  
   }
 
   public static void main(String[] args) {
      AbstractLogger loggerChain = getChainOfLoggers();
 
      loggerChain.logMessage(AbstractLogger.INFO, 
         "This is an information.");
 
      loggerChain.logMessage(AbstractLogger.DEBUG, 
         "This is an debug level information.");
 
      loggerChain.logMessage(AbstractLogger.ERROR, 
         "This is an error information.");
   }
}

result

复制代码
Standard Console::Logger: This is an information.
File::Logger: This is an debug level information.
Standard Console::Logger: This is an debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.

6 命令模式 Command Pattern

命令模式的本质是对请求进行封装,一个请求对应于一个命令, 将发出命令的责任和执行命令的责任分割开。

每一个命令都是一个操作:

  • 请求的一方发出请求要求执行一个操作;
  • 接收的一方收到请求,并执行相应的操作。

命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

命令模式的关键在于引入了抽象命令类,请求发送者针对抽象命令类编程,只有实现了抽象命令类的具体命令才与请求接收者相关联。在最简单的抽象命令类中只包含了一个抽象的execute()方法,每个具体命令类将一个Receiver类型的对象作为一个实例变量进行存储,从而具体指定一个请求的接收者,不同的具体命令类提供了execute()方法的不同实现,并调用不同接收者的请求处理方法。

6.1 Command 抽象命令类

抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。

6.2 ConcreteCommand 具体命令类

定义一个接收者和行为之间的弱耦合, 具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。

6.3 Invoker 请求者

通过命令对象来执行请求。 一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。

6.4 Receiver 接收者

具体实施和执行一个请求,任何一个类都可以成为接收者。

6.5 例子

  • AudioPlayer 接收者
  • Command 抽象命令
  • PlayCommand 具体命令
  • RewindCommand 具体命令
  • StopCommand 具体命令
  • Keypad 请求者
java 复制代码
public class AudioPlayer {
    
    public void play(){
        System.out.println("播放...");
    }
    
    public void rewind(){
        System.out.println("倒带...");
    }
    
    public void stop(){
        System.out.println("停止...");
    }
}
java 复制代码
public interface Command {
    public void execute();
}
java 复制代码
public class PlayCommand implements Command {

    private AudioPlayer myAudio;
    
    public PlayCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.play();
    }
}
java 复制代码
public class RewindCommand implements Command {

    private AudioPlayer myAudio;
    
    public RewindCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.rewind();
    }
}
java 复制代码
public class StopCommand implements Command {
    private AudioPlayer myAudio;
    
    public StopCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.stop();
    }
}
java 复制代码
public class Keypad {
    private Command playCommand;
    private Command rewindCommand;
    private Command stopCommand;
    
    public void setPlayCommand(Command playCommand) {
        this.playCommand = playCommand;
    }
    public void setRewindCommand(Command rewindCommand) {
        this.rewindCommand = rewindCommand;
    }
    public void setStopCommand(Command stopCommand) {
        this.stopCommand = stopCommand;
    }
    /**
     * 执行播放方法
     */
    public void play(){
        playCommand.execute();
    }
    /**
     * 执行倒带方法
     */
    public void rewind(){
        rewindCommand.execute();
    }
    /**
     * 执行播放方法
     */
    public void stop(){
        stopCommand.execute();
    }
}

client

java 复制代码
public class Julia {
    public static void main(String[]args){
        //创建接收者对象
        AudioPlayer audioPlayer = new AudioPlayer();
        //创建命令对象
        Command playCommand = new PlayCommand(audioPlayer);
        Command rewindCommand = new RewindCommand(audioPlayer);
        Command stopCommand = new StopCommand(audioPlayer);
        //创建请求者对象
        Keypad keypad = new Keypad();
        keypad.setPlayCommand(playCommand);
        keypad.setRewindCommand(rewindCommand);
        keypad.setStopCommand(stopCommand);
        //测试
        keypad.play();
        keypad.rewind();
        keypad.stop();
        keypad.play();
        keypad.stop();
    }
}

result

复制代码
播放...
倒带...
停止...
播放...
停止...

7 备忘录模式 Memento Pattern

备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复至原先保存的状态。

7.1 备忘录 (Memento)角色

  1. 将发起人(Originator)对象的内部状态存储起来。
  2. 备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态。
  3. 备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取。

7.2 发起人 (Originator)角色

  1. 创建一个含有当前的内部状态的备忘录对象。
  2. 使用备忘录对象存储其内部状态。

7.3 负责人 (Caretaker)角色

  1. 负责保存备忘录对象。
  2. 不检查备忘录对象的内容。

7.4 例子

  • Memento 备忘录
  • Originator 发起人
  • Caretaker 负责人
java 复制代码
public class Originator {

    private String state;
    /** 工厂方法,返回一个新的备忘录对象 */
    public Memento createMemento(){
        return new Memento(state);
    }
    /** 将发起人恢复到备忘录对象所记载的状态 */
    public void restoreMemento(Memento memento){
        this.state = memento.getState();
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
        System.out.println("当前状态:" + this.state);
    }
}
java 复制代码
public class Memento {
    
    private String state;
    
    public Memento(String state){
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    
}
java 复制代码
public class Caretaker {

    private Memento memento;
    /** 备忘录的取值方法 */
    public Memento retrieveMemento(){
        return this.memento;
    }
    /** 备忘录的赋值方法 */
    public void saveMemento(Memento memento){
        this.memento = memento;
    }
}

client

java 复制代码
public class Client {

    public static void main(String[] args) {
        
        Originator o = new Originator();
        Caretaker c = new Caretaker();
        //改变负责人对象的状态
        o.setState("On");
        //创建备忘录对象,并将发起人对象的状态储存起来
        c.saveMemento(o.createMemento());
        //修改发起人的状态
        o.setState("Off");
        //恢复发起人对象的状态
        o.restoreMemento(c.retrieveMemento());
        
        System.out.println(o.getState());
    }

}

7.5 黑箱备忘录模式

备忘录角色对发起人(Originator)角色对象提供一个宽接口,而为其他对象提供一个窄接口。这样的实现叫做"黑箱实现"。

在JAVA语言中,实现双重接口的办法就是将备忘录角色类设计成发起人角色类的内部成员类。

将Memento设成Originator类的内部类,从而将Memento对象封装在Originator里面;在外部提供一个标识接口MementoIF给Caretaker以及其他对象。这样,Originator类看到的是Menmento的所有接口,而Caretaker以及其他对象看到的仅仅是标识接口MementoIF所暴露出来的接口。

java 复制代码
public interface MementoIF { }
java 复制代码
public class Originator {

    private String state;
    
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
        System.out.println("赋值状态:" + state);
    }
    /**
     * 工厂方法,返还一个新的备忘录对象
     */
    public MementoIF createMemento(){
        return new Memento(state);
    }
    /**
     * 发起人恢复到备忘录对象记录的状态
     */
    public void restoreMemento(MementoIF memento){
        this.setState(((Memento)memento).getState());
    }
    
    private class Memento implements MementoIF{
        
        private String state;
        /**
         * 构造方法
         */
        private Memento(String state){
            this.state = state;
        }
        
        private String getState() {
            return state;
        }
        private void setState(String state) {
            this.state = state;
        }
    }
}
java 复制代码
public class Caretaker {

    private MementoIF memento;
    /**
     * 备忘录取值方法
     */
    public MementoIF retrieveMemento(){
        return memento;
    }
    /**
     * 备忘录赋值方法
     */
    public void saveMemento(MementoIF memento){
        this.memento = memento;
    }
}
java 复制代码
public class Client {

    public static void main(String[] args) {
        Originator o = new Originator();
        Caretaker c = new Caretaker();
        //改变负责人对象的状态
        o.setState("On");
        //创建备忘录对象,并将发起人对象的状态存储起来
        c.saveMemento(o.createMemento());
        //修改发起人对象的状态
        o.setState("Off");
        //恢复发起人对象的状态
        o.restoreMemento(c.retrieveMemento());
    }

}

8 状态模式 State Pattern

状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。

状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是 让一个对象在其内部状态改变的时候,其行为也随之改变。

8.1 角色

  • 环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
  • 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
  • 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

8.2 例子

java 复制代码
public class Context {
    //持有一个State类型的对象实例
    private State state;

    public void setState(State state) {
        this.state = state;
    }
    /**
     * 用户感兴趣的接口方法
     */
    public void request(String sampleParameter) {
        //转调state来处理
        state.handle(sampleParameter);
    }
}
java 复制代码
public interface State {
    /** 状态对应的处理 */
    public void handle(String sampleParameter);
}
java 复制代码
public class ConcreteStateA implements State {

    @Override
    public void handle(String sampleParameter) {
        System.out.println("ConcreteStateA handle :" + sampleParameter);
    }

}
java 复制代码
public class ConcreteStateB implements State {

    @Override
    public void handle(String sampleParameter) {
        System.out.println("ConcreteStateB handle :" + sampleParameter);
    }

}

client

java 复制代码
public class Client {

    public static void main(String[] args){
        //创建状态
        State state = new ConcreteStateB();
        //创建环境
        Context context = new Context();
        //将状态设置到环境中
        context.setState(state);
        //请求
        context.request("test");
    }
}

环境类Context的行为request()是委派给某一个具体状态类的。通过使用多态性原则,可以动态改变环境类Context的属性State的内容,使其从指向一个具体状态类变换到指向另一个具体状态类,从而使环境类的行为request()由不同的具体状态类来执行。

9 访问者模式 Visitor Pattern

我们使用了一个访问者类,它改变了元素类的执行算法。元素的执行算法可以随着访问者改变而改变。

可以在不改变数据结构的前提下定义作用于这些元素的新的操作。因此适用于数据结构相对固定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。

数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。

9.1 角色

抽象访问者:

抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。

访问者:

实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。

抽象元素类:

接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。

元素类:

实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。

结构对象

一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。

9.2 例子

java 复制代码
abstract class Element {  
    public abstract void accept(IVisitor visitor);  
    public abstract void doSomething();  
}  
java 复制代码
class ConcreteElement1 extends Element {  
    public void doSomething(){  
        System.out.println("这是元素1");  
    }  
      
    public void accept(IVisitor visitor) {  
        visitor.visit(this);  
    }  
}  
  
class ConcreteElement2 extends Element {  
    public void doSomething(){  
        System.out.println("这是元素2");  
    }  
      
    public void accept(IVisitor visitor) {  
        visitor.visit(this);  
    }  
} 
java 复制代码
interface IVisitor {  
    public void visit(ConcreteElement1 el1);  
    public void visit(ConcreteElement2 el2);  
}
java 复制代码
class Visitor implements IVisitor {  
  
    public void visit(ConcreteElement1 el1) {  
        el1.doSomething();  
    }  
      
    public void visit(ConcreteElement2 el2) {  
        el2.doSomething();  
    }  
}
java 复制代码
class ObjectStruture {  
    public static List<Element> getList(){  
        List<Element> list = new ArrayList<Element>();  
        Random ran = new Random();  
        for(int i=0; i<10; i++){  
            int a = ran.nextInt(100);  
            if(a>50){  
                list.add(new ConcreteElement1());  
            }else{  
                list.add(new ConcreteElement2());  
            }  
        }  
        return list;  
    }  
} 
java 复制代码
public class Client {  
    public static void main(String[] args){  
        List<Element> list = ObjectStruture.getList();  
        for(Element e: list){  
            e.accept(new Visitor());  
        }  
    }  
} 

10 中介者模式 Mediator Pattern

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

10.1 例子

java 复制代码
//定义抽象Mediator,可以与同时们进行联络
public abstract class Mediator {
    public abstract void contact(String content,Colleague coll);
}
java 复制代码
public class Colleague {
    protected String name;
    protected Mediator mediator;

    public Colleague(String name, Mediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }
}
java 复制代码
public class ColleagueA extends Colleague {

    // 具体同事类继承自Colleague,此刻就可以与中介者mediator进行通信了
    public ColleagueA(String name, Mediator mediator) {
        super(name, mediator);
    }
    public void getMessage(String message){
        System.out.println("同事A"+name+"获得信息"+message);
    }
    //同事A与中介者通信
    public void contact(String message){
        mediator.contact(message, this);
    }
}
public class ColleagueB extends Colleague {

    public ColleagueB(String name, Mediator mediator) {
        super(name, mediator);
    }
    public void getMessage(String message){
        System.out.println("同事B"+name+"获得信息"+message);
    }
    //同事B与中介者通信
    public void contact(String message){
        mediator.contact(message, this);
    }
}
java 复制代码
//定义具体中介者ConcreteMediator,具体中介者通过协调各同事对象实现协作行为,了解并维护它的各个同事。
public class ConcreteMediator extends Mediator {
    ColleagueA collA;
    ColleagueB collB;

    public ColleagueA getCollA() { return collA; }
    public void setCollA(ColleagueA collA) { this.collA = collA; }

    public ColleagueB getCollB() { return collB; }
    public void setCollB(ColleagueB collB) { this.collB = collB; }

    @Override
    public void contact(String content, Colleague coll) {
        if (coll==collA) {
            collB.getMessage(content);
        } else {
            collA.getMessage(content);
        }
    }
}

client

java 复制代码
public class Client {

    // 中介者,ColleagueA、ColleagueB
    public static void main(String[] args) {
        // 定义中介者
        ConcreteMediator mediator = new ConcreteMediator();
        // 定义具体同事类
        ColleagueA colleagueA = new ColleagueA("张三", mediator);
        ColleagueB colleagueB = new ColleagueB("李四", mediator);
        // 中介者知晓每一个具体的Colleague类
        mediator.setCollA(colleagueA);
        mediator.setCollB(colleagueB);

        colleagueA.contact("我是A,我要和同事B说说工作的事情");
        colleagueB.contact("我是B,我下午有时间,下午商量吧");
    }

}

result

复制代码
同事B李四获得信息:我是A,我要和同事B说说工作的事情
同事A张三获得信息:我是B,我下午有时间,下午商量吧

11 解释器模式 Interpreter Pattern

解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。

这种模式可被用在 SQL 解析、符号处理引擎等。比如mongodb中的查询语句。

11.1 例子

java 复制代码
public interface Expression {
   public boolean interpret(String context);
}
java 复制代码
public class TerminalExpression implements Expression {
   
   private String data;
 
   public TerminalExpression(String data){
      this.data = data; 
   }
 
   @Override
   public boolean interpret(String context) {
      if(context.contains(data)){
         return true;
      }
      return false;
   }
}
java 复制代码
public class OrExpression implements Expression {
    
   private Expression expr1 = null;
   private Expression expr2 = null;
 
   public OrExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }
 
   @Override
   public boolean interpret(String context) {      
      return expr1.interpret(context) || expr2.interpret(context);
   }
}
java 复制代码
public class AndExpression implements Expression {
    
   private Expression expr1 = null;
   private Expression expr2 = null;
 
   public AndExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }
 
   @Override
   public boolean interpret(String context) {      
      return expr1.interpret(context) && expr2.interpret(context);
   }
}

client

java 复制代码
public class Client {
 
   //规则:Robert 和 John 是男性
   public static Expression getMaleExpression(){
      Expression robert = new TerminalExpression("Robert");
      Expression john = new TerminalExpression("John");
      return new OrExpression(robert, john);    
   }
 
   //规则:Julie 是一个已婚的女性
   public static Expression getMarriedWomanExpression(){
      Expression julie = new TerminalExpression("Julie");
      Expression married = new TerminalExpression("Married");
      return new AndExpression(julie, married);    
   }
 
   public static void main(String[] args) {
      Expression isMale = getMaleExpression();
      Expression isMarriedWoman = getMarriedWomanExpression();
 
      System.out.println("John is male? " + isMale.interpret("John"));
      System.out.println("Julie is a married women? " 
      + isMarriedWoman.interpret("Married Julie"));
   }
}

result

复制代码
John is male? true
Julie is a married women? true
相关推荐
zhuiQiuMX12 分钟前
笔试阶段性心得总结
java·python
星沁城1 小时前
236. 二叉树的最近公共祖先
java·数据结构·leetcode·二叉树
oliveira-time2 小时前
Java 1.8(也称为Java 8)
java·开发语言
极小狐4 小时前
如何使用极狐GitLab 软件包仓库功能托管 maven?
java·运维·数据库·安全·c#·gitlab·maven
.生产的驴4 小时前
SpringBoot 集成滑块验证码AJ-Captcha行为验证码 Redis分布式 接口限流 防爬虫
java·spring boot·redis·分布式·后端·爬虫·tomcat
野犬寒鸦6 小时前
MySQL索引使用规则详解:从设计到优化的完整指南
java·数据库·后端·sql·mysql
思考的橙子6 小时前
Springboot之会话技术
java·spring boot·后端
钰爱&6 小时前
【Linux】POSIX 线程信号量与互斥锁▲
java·开发语言·jvm
yt948327 小时前
Matlab实现绘制任意自由曲线
开发语言·matlab
黑匣子~8 小时前
java集成telegram机器人
java·python·机器人·telegram