设计模式——行为型模式

行为型模式

行为型模式主要是用于描述类或者对象是怎样交互和怎样分配职责的。它涉及到算法和对象间的职责分配,不仅描述对象或者类的模式,还描述了他们之间的通信方式,它将你的注意力从控制流转移到了对象间的关系上来。行为型类模式采用继承机制在类间分派行为,而行为型对象模式使用对象复合而不是继承。它主要包括以下11种设计模式:职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。

十二、职责链模式

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止,这就是职责链模式。

12.1 前言

  • 学生请假

    image-20200913091349548

    学校规定所以去参加校招的必须要请假,且必须要有相关人员的签字,三天一下,辅导员签字、三到七天系主任签字,一个星期以上院长签字。对于这种将请求一级一级地往上传递直到处理请求为止的设计模式就是职责链模式。

  • 网络数据传输

    在计算机软硬件中也有相关例子,如总线网中数据报传送,每台计算机根据目标地址是否同自己的地址相同来决定是否接收;还有异常处理中,处理程序根据异常的类型决定自己是否处理该异常;还有 Struts2 的拦截器、JSP 和 Servlet 的 Filter 等,所有这些,如果用责任链模式都能很好解决。

12.2 概述

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止,这就是职责链模式。

在职责链模式中最关键的一点就是客户提交请求后,请求沿着链往下传递直到有一个处理者处理它,在这里客户无需关心它的请求是哪个处理者来处理,反正总有一个处理者会处理它的请求。

在这里客户端和处理者都没有对方明确的信息,同时处理者也不知道职责链中的结构。所以职责链可以简化对象的相互连接,他们只需要保存一个指向其后续者的引用,而不需要保存所有候选者的引用。

在职责链模式中我们可以随时随地的增加或者更改一个处理者,甚至可以更改处理者的顺序,增加了系统的灵活性。处理灵活性是增加了,但是有时候可能会导致一个请求无论如何也得不到处理,它会被放置在链末端,这个既是职责链的优点也是缺点。

12.2.1 类图
image-20200913101257925
  • Handler:抽象处理者。定义了一个处理请求的方法,所有的处理者都必须实现该抽象类。它拥有一个handlerRequest方法,用来接收需要处理的请求。
  • ConcreteHandler:具体处理者。处理它所负责的请求,同时也可以访问它的后继者。如果它能够处理该请求则处理,否则将请求传递到它的后继者。每个具体处理器都维持一个引用,指向链中下一个具体处理器,需要检查它自身是否能处理这个请求,不能就将请求传递给链中下一个具体处理器。
  • Client:客户类。 客户端是使用责任链模式的应用程序的主要结构。它的职责是实例化一个处理器的链,然后在第一个对象种调用handlerRequest方法。
12.2.2 适用场景
  1. 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
  2. 可动态指定一组对象处理请求,或添加新的处理者。
  3. 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。

12.3 实现

用责任链模式设计一个请假条审批模块:

假如规定学生请假小于或等于 2 天,班主任可以批准;小于或等于 7 天,系主任可以批准;小于或等于 10 天,院长可以批准;其他情况不予批准。

首先,定义一个领导类(Leader),它是抽象处理者,包含了一个指向下一位领导的指针 next 和一个处理假条的抽象处理方法 handleRequest(int LeaveDays);然后,定义班主任类(ClassAdviser)、系主任类(DepartmentHead)和院长类(Dean),它们是抽象处理者的子类,是具体处理者,必须根据自己的权力去实现父类的 handleRequest(int LeaveDays) 方法,如果无权处理就将假条交给下一位具体处理者,直到最后;客户类负责创建处理链,并将假条交给链头的具体处理者(班主任)。

image-20200913111717431
/**
 * 抽象处理器类
 * 领导类
 */
public abstract class Leader {
   

    // 设置职责链中的下一个处理器对象
    private Leader next;
    // 职责链的设置由客户端定义
    public void setNext(Leader next)
    {
   
        this.next=next;
    }
    public Leader getNext()
    {
   
        return next;
    }
    //处理请求的方法
    public abstract void handleRequest(int LeaveDays);

}
/**
 * 具体处理器
 * 班主任类
 */
public class ClassAdviser extends Leader {
   

    @Override
    public void handleRequest(int LeaveDays) {
   
        if(LeaveDays<=2)
        {
   
            System.out.println("班主任批准您请假" + LeaveDays + "天。");
        }
        else
        {
   
            if(getNext() != null)
            {
   
                this.getNext().handleRequest(LeaveDays);
            }
            else
            {
   
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}

/**
 * 具体处理器
 * 系主任类
 */
public class DepartmentHead extends Leader {
   
    @Override
    public void handleRequest(int LeaveDays) {
   
        if(LeaveDays<=7)
        {
   
            System.out.println("系主任批准您请假" + LeaveDays + "天。");
        }
        else
        {
   
            if(getNext() != null)
            {
   
                getNext().handleRequest(LeaveDays);
            }
            else
            {
   
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}

/**
 * 具体处理器类
 * 院长类
 */
public class Dean extends Leader {
   
    @Override
    public void handleRequest(int LeaveDays) {
   
        if(LeaveDays<=10)
        {
   
            System.out.println("院长批准您请假" + LeaveDays + "天。");
        }
        else
        {
   
            if(getNext() != null)
            {
   
                getNext().handleRequest(LeaveDays);
            }
            else
            {
   
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}

/**
 * 具体处理器
 * 教务处长
 */
public class DeanOfStudies extends Leader {
   
    @Override
    public void handleRequest(int LeaveDays) {
   
        if(LeaveDays<=20)
        {
   
            System.out.println("教务处长批准您请假"+LeaveDays+"天。");
        }
        else
        {
   
            if(getNext()!=null)
            {
   
                getNext().handleRequest(LeaveDays);
            }
            else
            {
   
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}
// 客户端
public class Client {
   

    public static void main(String[] args)
    {
   
        //组装责任链
        Leader teacher1=new ClassAdviser();
        Leader teacher2=new DepartmentHead();
        Leader teacher3=new Dean();
        //Leader teacher4=new DeanOfStudies();
        
        // 由客户端来自定义职责链
        teacher1.setNext(teacher2);
        teacher2.setNext(teacher3);
        //teacher3.setNext(teacher4);
        
        //提交请求
        teacher1.handleRequest(8);
    }

}

12.4 特点

在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。

12.4.1 优点

责任链模式是一种对象行为型模式,其主要优点如下。

  1. 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
  2. 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
  3. 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
  4. 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
  5. 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
12.4.2 缺点

其主要缺点如下。

  1. 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  2. 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  3. 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

12.5 总结

  • 职责链模式将请求的发送者和接受者解耦了。客户端不需要知道请求处理者的明确信息,甚至不需要知道链的结构,它只需要将请求进行发送即可。

  • 职责链模式能够非常方便的动态增加新职责或者删除职责。

  • 客户端发送的请求可能会得不到处理。

  • 处理者不需要知道链的结构,只需要明白他的后续者是谁就可以了。这样就简化了系统中的对象。

十三、命令模式

命令模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

13.1 前言

在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

在现实生活中,这样的例子也很多:

  • 电视机遥控器 : 遥控器是请求的发送者,电视机是请求的接收者,遥控器上有一些按钮如开,关,换频道等按钮就是具体命令,不同的按钮对应电视机的不同操作。

13.2 概述

命令模式将请求封装成对象,以便可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式可以对发送者额接受者完全解耦,发送者也接收者之间并没有直接的联系,发送者只需要知道如何发送请求,不需要关心请求是如何完成了。这就是命令模式,命令模式将方法调用给封装起来了。

13.2.1 类图

image-20200914105855096

  • **抽象命令类(Command):**声明执行操作的接口。调用接收者相应的操作,以实现执行的方法Execute。

  • **具体命令类(ConcreteCommand):**创建一个具体命令对象并设定它的接收者。通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。

  • **调用者(Invoker):**要求该命令执行这个请求。通常会持有命令对象,可以持有很多的命令对象。这是触发命令的类,通常是外部事件,例如用户操作。

  • **接收者(Receiver):**知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者,只要它能够实现命令要求实现的相应功能。 负责执行与命令关联的操作的类。

  • **客户类(Client):**创建具体的命令对象,并且设置命令对象的接收者。真正使用命令的客户端是从Invoker来触发执行。

命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,使得发送者只需要知道如何发送命令即可,不需要命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。

13.2.2 适用场景
  1. 当系统需要将请求调用者与请求接收者解耦时,命令模式使得调用者和接收者不直接交互。
  2. 当系统需要随机请求命令或经常增加或删除命令时,命令模式比较方便实现这些功能。
  3. 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
  4. 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。

13.3 实现

/**
 * 抽象命令类
 * 声明执行操作的接口
 * 定义execute函数,引导各个具体实现类应该执行哪个命令
 */
public interface Command {
   

    public void execute();

}
/**
 * 具体命令类
 * 关联一个接收者对象,由于接收者内含有与命令有关的操作
 * 所以该类就实现了命令的发出与执行之间的解耦
 */
public class OpenTvCommand implements Command {
   

    // 关联一个接收者对象
    private Television tv;

    public OpenTvCommand() {
   
        tv = new Television();
    }

    @Override
    public void execute() {
   
        tv.open();
    }
}

public class ChangeChannelCommand implements Command {
   

    private Television tv;

    public ChangeChannelCommand() {
   
        this.tv = new Television();
    }

    @Override
    public void execute() {
   
        tv.changeChannel();
    }
}

public class CloseTvCommand implements Command {
   

    private Television tv;

    public CloseTvCommand() {
   
        this.tv = new Television();
    }

    @Override
    public void execute() {
   
        tv.close();
    }
}

/**
 * 接收者类
 * 面向客户端的统一接口
 * 负责执行与命令关联的操作
 */
public class Television {
   

    public void open(){
   
        System.out.println("打开电视机......");
    }

    public void close(){
   
        System.out.println("关闭电视机......");
    }

    public void changeChannel(){
   

        System.out.println("切换电视频道......");
    }

}
/**
 * 调用者
 * 触发命令的执行
 * 该类是一个外部类,要求该命令执行这个请求
 */
public class Controller {
   

    private Command command;

    public void setCommand(Command command) {
   
        this.command = command;
    }

    /**
     * 打开电视剧
     */
    public void open(){
   
        command.execute();
    }

    /**
     * 关闭电视机
     */
    public void close(){
   
        command.execute();
    }

    /**
     * 换频道
     */
    public void change(){
   

        command.execute();
    }
}
public class Client {
   

    public static void main(String a[])
    {
   
        Command openCommand,closeCommand,changeCommand;

        // 定义具体命令
        openCommand = new OpenTvCommand();
        closeCommand = new CloseTvCommand();
        changeCommand = new ChangeChannelCommand();

        // 调用者
        Controller control = new Controller();
        // 调用者设置要执行的命令
        control.setCommand(openCommand);
        control.open();           //打开电视机

        control.setCommand(changeCommand);
        control.change();         //换频道

        control.setCommand(closeCommand);
        control.close();          //关闭电视机
    }

}

13.4 特点

13.4.1 优点
  • 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。

  • Command是头等的对象,增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。

  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。

  • 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。

宏命令又称为组合命令,它是命令模式和组合模式联用的产物:

宏命令也是一个具体命令,不过它包含了对其他命令对象的引用,在调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法,一个宏命令的成员对象可以是简单命令,还可以继续是宏命令。执行一个宏命令将执行多个具体命令,从而实现对命令的批处理。

13.4.2 缺点

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

13.5 总结

1)命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。

2)每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作

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

4)命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。

5)命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

十四、解释器模式

给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

14.1 前言

  • 在软件开发中,会遇到有些问题多次重复出现,而且有一定的相似性和规律性。如果将它们归纳成一种简单的语言,那么这些问题实例将是该语言的一些句子,这样就可以用“编译原理”中的解释器模式来实现了。
  • 为人处事是一门大学问,察言观色、听懂弦外之音都是非常重要的,老板跟你说“XX你最近表现平平啊,还得要多努力”,如果你不当回事,平常对待,可能下次就是“XX,恩,你人还是不错,平常工作也很努力,但是我想这份工作可能不是很适合你……”。又比如你老大说“XX,你最近表现不错,工作积极性很高啊!继续保持啊!”,你高兴乐呵着心想是不是老板要给我加工资了,可能你等到花都谢了也没有,得到的可能会是更多的工作量。对于我们刚刚入社会的人不够圆滑,不会察言观色,更听不懂老板的弦外之音,所以我们期待如果有一个翻译机该多好,直接将别人的弦外之音给翻译出来就好了。
  • 有个游戏,输入up walk 5,玩家必须按照:移动方向+移动方式+移动距离这种格式输入我的指令,而这种格式的指令就是一种文法,只有按照了我定义的这种文法去输入,才能控制屏幕上的小狗去移动。当然了,我输入up walk 5,屏幕上的小狗肯定是听不懂的,它不知道我输入的是什么,这个时候需要怎么办?我需要一个工具去将我输入的内容翻译成小狗能听懂的东西,而这个工具就是定义中提到的解释器,解释器对我输入的指令进行解释,然后将解释得到的指令发送给屏幕上的小狗,小狗听懂了,就进行实际的移动。

虽然使用解释器模式的实例不是很多,但对于满足以上特点,且对运行效率要求不是很高的应用实例,如果用解释器模式来实现,其效果是非常好的,本文将介绍其工作原理与使用方法。

14.2 概述

**给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。**解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发的编译器中。它描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。

14.2.1 文法与句子

文法是用于描述语言的语法结构的形式规则。

句子是语言的基本单位,是语言集中的一个元素,它由终结符构成,能由“文法”推导出。

〈句子〉::=〈主语〉〈谓语〉〈宾语〉
〈主语〉::=〈代词〉|〈名词〉
〈谓语〉::=〈动词〉
〈宾语〉::=〈代词〉|〈名词〉
〈代词〉::=你|我|他
〈名词〉::=大学生|筱霞|英语
〈动词〉::=是|学习

根据上述文法可以推导出句子为“我是大学生”。

注:这里的符号“::=”表示“定义为”的意思,用“〈”和“〉”括住的是非终结符,没有括住的是终结符。

14.2.2 抽象语法树

当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

  • 该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。

  • 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。

以上述的游戏例子为例,可以定义以下五条文法:

expression ::= direction action distance | composite //表达式
composite ::= expression 'and' expression //复合表达式
direction ::= 'up' | 'down' | 'left' | 'right' //移动方向
action ::= 'move' | 'walk' //移动方式
distance ::= an integer //移动距离
  • 上面的5条文法规则,对应5个语言单位,这些语言单位可以分为两大类:一类为终结符(也叫做终结符表达式),例如上面的direction、action和distance,它们是语言的最小组成单位,不能再进行拆分;另一类为非终结符(也叫做非终结符表达式),例如上面的expression和composite,它们都是一个完整的句子,包含一系列终结符或非终结符。

  • 我们就是根据上面定义的一些文法可以构成更多复杂的语句,计算机程序将根据这些语句进行某种操作;而我们这里列出的文法,计算机是无法直接看懂的,所以,我们需要对我们定义的文法进行解释;就好比,我们编写的C++代码,计算机是看不懂的,我们需要进行编译一样。解释器模式,就提供一种模式去给计算机解释我们定义的文法,让计算机根据我们的文法去进行工作。

  • 文法规则定义中可以使用一些符号来表示不同的含义,如使用“|”表示或,使用“{”和“}”表示组合,使用“*”表示出现0次或多次等,其中使用频率最高的符号是表示“或”关系的“|”,如文法规则“bool Value ::= 0 | 1”表示终结符表达式bool Value的取值可以为0或者1。

  • 除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树的图形方式来直观地表示语言的构成,每一棵语法树对应一个语言实例,对于上面的游戏文法规则,可以通过以下的抽象语法树来进行表示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KflMiiC2-1625839249477)(https://segmentfault.com/img/bVU2OR?w=893&h=629/view)]

14.2.3 类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-448JocBf-1625839249478)(E:\我的资料\study\upload\image-20200915091552297.png)]

  • **AbstractExpression(抽象表达式):**声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享

  • TerminalExpression(终结符表达式): 实现与文法中的终结符相关联的解释操作。一个句子中的每个终结符需要该类的一个实例

  • NonterminalExpression(非终结符表达式): 为文法中的非终结符实现解释操作

    • 对于文法中的每一条规则都需要一个NonternimalExpression类;
    • 为文法中的的每个符号都维护一个AbstractExpression类型的实例变量;
    • 为文法中的非终结符实现解释操作,在实现时,一般要递归地调用表示文法符号的那些对象的解释操作;
  • Context(上下文): 包含解释器之外的一些全局信息

  • **Client(客户):**构建表示该文法定义的语言中一个特定的句子的抽象语法树。 该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。 即构建一个需要进行解释操作的文法句子,然后调用解释操作进行解释


实际进行解释时,按照以下时序进行的:

  • Client构建一个句子,它是NonterminalExpression和TerminalExpression的实例的一个抽象语法树,然后初始化上下文并调用解释操作;
  • 每一非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础;
  • 每一节点的解释操作用上下文来存储和访问解释器的状态
14.2.4 适用场景
  • 如果在系统中某一特定类型的问题发生的频率很高,此时可以考虑将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,该解释器通过解释这些句子来解决这些问题。
  • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  • 一些重复出现的问题可以用一种简单的语言来进行表达。
  • 一个简单语法需要解释的场景。

14.3 实现

用解释器模式设计一个“韶粵通”公交车卡的读卡器程序。

说明:假如“韶粵通”公交车读卡器可以判断乘客的身份,如果是“韶关”或者“广州”的“老人” “妇女”“儿童”就可以免费乘车,其他人员乘车一次扣 2 元。

分析:本实例用“解释器模式”设计比较适合,首先设计其文法规则如下。

<expression> ::= <city>的<person>
<city> ::= 韶关|广州
<person> ::= 老人|妇女|儿童

根据文法规则按以下步骤设计公交车卡的读卡器程序的类图。

  • 定义一个抽象表达式(Expression)接口,它包含了解释方法 interpret(String info)。
  • 定义一个终结符表达式(Terminal Expression)类,它用集合(Set)类来保存满足条件的城市或人,并实现抽象表达式接口中的解释方法 interpret(Stringinfo),用来判断被分析的字符串是否是集合中的终结符。
  • 定义一个非终结符表达式(AndExpressicm)类,它也是抽象表达式的子类,它包含满足条件的城市的终结符表达式对象和满足条件的人员的终结符表达式对象,并实现 interpret(String info) 方法,用来判断被分析的字符串是否是满足条件的城市中的满足条件的人员。
  • 最后,定义一个环境(Context)类,它包含解释器需要的数据,完成对终结符表达式的初始化,并定义一个方法 freeRide(String info) 调用表达式对象的解释方法来对被分析的字符串进行解释

其类图如下:

image-20200915095046289

/**
 * 抽象表达式类
 * 声明执行的解释方法
 */
public interface Expression {
   

    public boolean interpret(String info);

}
/**
 * 终结符表达式类
 * 实现与文法中的终结符相关联的解释操作
 * 终结符中定义了最根本的数据的设置
 */
public class TerminalExpression implements Expression {
   

    // 定义存储原始数据的集合
    private Set<<
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我姓弓长那个张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值