Leetcode-设计模式-行为型模式

Posted 钢铁-程序猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode-设计模式-行为型模式相关的知识,希望对你有一定的参考价值。

文章目录

行为型模式

一、责任链模式(责任链主要用于处理 职责相同,程度不同的类)

责任链模式的优点:

  • 降低对象之间的耦合
  • 扩展性强,符合开闭原则
  • 灵活性强
  • 简化对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用

缺点:

  • 如果责任链过长,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  • 不能保证每个请求一定被处理,该请求可能一直传到链的末端都得不到处理。

例子

新建一个程序员抽象类:

public abstract class Programmer 
    protected Programmer next;

    public void setNext(Programmer next) 
        this.next = next;
    

    abstract void handle(Bug bug);

在这个抽象类中:

  • next 对象表示如果自己解决不了,需要将责任传递给的下一个人;
  • handle 方法表示自己处理此 bug 的逻辑,在这里判断是自己解决或者继续传递。


新建菜鸟程序员类:

public class NewbieProgrammer extends Programmer 

    @Override
    public void handle(Bug bug) 
        if (bug.value > 0 && bug.value <= 20) 
            solve(bug);
         else if (next != null) 
            next.handle(bug);
        
    

    private void solve(Bug bug) 
        System.out.println("菜鸟程序员解决了一个难度为 " + bug.value + " 的 bug");
    

新建普通程序员类:

public class NormalProgrammer extends Programmer 

    @Override
    public void handle(Bug bug) 
        if (bug.value > 20 && bug.value <= 50) 
            solve(bug);
         else if (next != null) 
            next.handle(bug);
        
    

    private void solve(Bug bug) 
        System.out.println("普通程序员解决了一个难度为 " + bug.value + " 的 bug");
    

新建优秀程序员类:

public class GoodProgrammer extends Programmer 

    @Override
    public void handle(Bug bug) 
        if (bug.value > 50 && bug.value <= 100) 
            solve(bug);
         else if (next != null) 
            next.handle(bug);
        
    

    private void solve(Bug bug) 
        System.out.println("优秀程序员解决了一个难度为 " + bug.value + " 的 bug");
    

客户端测试:

import org.junit.Test;

public class Client4 
    @Test
    public void test() 
        NewbieProgrammer newbie = new NewbieProgrammer();
        NormalProgrammer normal = new NormalProgrammer();
        GoodProgrammer good = new GoodProgrammer();

        Bug easy = new Bug(20);
        Bug middle = new Bug(50);
        Bug hard = new Bug(100);

        // 组成责任链
        newbie.setNext(normal);
        normal.setNext(good);

        // 从菜鸟程序员开始,沿着责任链传递
        newbie.handle(easy);
        newbie.handle(middle);
        newbie.handle(hard);
    

二、命令模式(实现同一个接口,通过多态的方式调用方法,实现不同的命令功能)

请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

命令模式的主要优点如下:

  • 降低系统的耦合度。将 “行为请求者” 和 ”行为实现者“ 解耦。
  • 扩展性强。增加或删除命令非常方便,并且不会影响其他类。
  • 封装 “方法调用”,方便实现 Undo 和 Redo 操作。
  • 灵活性强,可以实现宏命令。

它的主要缺点是:

  • 会产生大量命令类。增加了系统的复杂性。

例子

创建一个命令接口。

Order.java
public interface Order 
   void execute();

步骤 2
创建一个请求类。

Stock.java

public class Stock 
   
   private String name = "ABC";
   private int quantity = 10;
 
   public void buy()
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] bought");
   
   public void sell()
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] sold");
   

步骤 3
创建实现了 Order 接口的实体类。

BuyStock.java

public class BuyStock implements Order 
   private Stock abcStock;
 
   public BuyStock(Stock abcStock)
      this.abcStock = abcStock;
   
 
   public void execute() 
      abcStock.buy();
   

SellStock.java

public class SellStock implements Order 
   private Stock abcStock;
 
   public SellStock(Stock abcStock)
      this.abcStock = abcStock;
   
 
   public void execute() 
      abcStock.sell();
   

步骤 4
创建命令调用类。

Broker.java

import java.util.ArrayList;
import java.util.List;
 
public class Broker 
   private List<Order> orderList = new ArrayList<Order>(); 
 
   public void takeOrder(Order order)
      orderList.add(order);      
   
 
   public void placeOrders()
      for (Order order : orderList) 
         order.execute();
      
      orderList.clear();
   

步骤 5
使用 Broker 类来接受并执行命令。

CommandPatternDemo.java

public class CommandPatternDemo 
   public static void main(String[] args) 
      Stock abcStock = new Stock();
 
      BuyStock buyStockOrder = new BuyStock(abcStock);
      SellStock sellStockOrder = new SellStock(abcStock);
 
      Broker broker = new Broker();
      broker.takeOrder(buyStockOrder);
      broker.takeOrder(sellStockOrder);
 
      broker.placeOrders();
   

步骤 6
执行程序,输出结果:

Stock [ Name: ABC, Quantity: 10 ] bought
Stock [ Name: ABC, Quantity: 10 ] sold
我们期待能有一种设计,让遥控器不需要知道家居的接口。它只需要负责监听用户按下开关,再根据开关状态发出正确的命令,对应的家居在收到命令后做出响应。就可以达到将 “行为请求者” 和 ”行为实

三、解释器模式(若问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题)

面向过程编程会有耦合度高,不易扩展等缺点

如何解决:构建语法树,定义终结符与非终结符。
在解释器模式中,我们将不可拆分的最小单元称之为终结表达式,可以被拆分的表达式称之为非终结表达式。

解释器模式中常用到递归,递归解析语句。

使用场景:

  • 1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  • 2、一些重复出现的问题可以用一种简单的语言来进行表达。
  • 3、一个简单语法需要解释的场景。

例子

步骤 1
创建一个表达式接口。

public interface Expression 
   public boolean interpret(String context);

步骤 2
创建实现了上述接口的实体类。

TerminalExpression.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;
   

OrExpression.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);
   

AndExpression.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);
   

步骤 3
InterpreterPatternDemo 使用 Expression 类来创建规则,并解析它们。

InterpreterPatternDemo.java

public class InterpreterPatternDemo 
 
   //规则: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"));
   

步骤 4
执行程序,输出结果:

John is male? true
Julie is a married women? true

四、迭代器模式(提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节)

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

何时使用:多个类相互耦合,形成了网状结构。

如何解决:将上述网状结构分离为星型结构。

例子


创建中介类。

ChatRoom.java

import java.util.Date;
 
public class ChatRoom 
   public static void showMessage(User user, String message)
      System.out.println(new Date().toString()
         + " [" + user.getName() +"] : " + message);
   

步骤 2
创建 user 类。

User.java

public class User 
   private String name;
 
   public String getName() 
      return name;
   
 
   public void setName(String name) 
      this.name = name;
   
 
   public User(String name)
      this.name  = name;
   
 
   public void sendMessage(String message)
      ChatRoom.showMessage(this,message);
   

步骤 3
使用 User 对象来显示他们之间的通信。

MediatorPatternDemo.java

public class MediatorPatternDemo 
   public static void main(String[] args) 
      User robert = new User("Robert");
      User john = new User("John");
 
      robert.sendMessage("Hi! John!");
      john.sendMessage("Hello! Robert!");
   

步骤 4
执行程序,输出结果:

Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John!
Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!

六、备忘录模式(在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态)

主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

如何解决:通过一个备忘录类专门存储对象状态。

例子

备忘录模式使用三个类 Memento、Originator 和 CareTaker。Memento 包含了要被恢复的对象的状态。Originator 创建并在 Memento 对象中存储状态。Caretaker 对象负责从 Memento 中恢复对象的状态。


创建 Memento 类。

Memento.java

public class Memento 
   private String state;
 
   public Memento(String state)
      this.state = state;
   
 
   public String getState()
      return state;
     

步骤 2
创建 Originator 类。

Originator.java

public class Originator 
   private String state;
 
   public void setState(String state)
      this.state = state;
   
 
   public String getState()
      return state;
   
 
   public Memento saveStateToMemento()
      return new Memento(state);
   
 
   public void getStateFromMemento(Memento Memento)
      state = Memento.getState();
   

步骤 3
创建 CareTaker 类。

CareTaker.java

import java.util.ArrayList;
import java.util.List;
 
public class CareTaker 
   private List<Memento> mementoList = new ArrayList<Memento>();
 
   public void add(Memento state)
      mementoList.add(state);
   
 
   public Memento get(int index)
      return mementoList.get(index);
   

步骤 4
使用 CareTaker 和 Originator 对象。

MementoPatternDemo.java

public class MementoPatternDemo 
   public static void main(以上是关于Leetcode-设计模式-行为型模式的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode-设计模式-行为型模式

UOJ #596. 罪犯分组

[CF868E]Policeman and a Tree

设计模式值职责链模式(行为型)

设计模式 行为型模式 -- 行为型模式概述

设计模式——行为型模式