设计模式-解释器模式、装饰器模式

发布于:2025-02-24 ⋅ 阅读:(115) ⋅ 点赞:(0)

解释器模式

定义

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

类图

角色

  • 抽象表达式( Abstract Expression) 角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()

  • 终结符表达式(Terminal Expression) 角色: 是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每个终结符都有一个具体终结表达式与之相对应。

  • 非终结符表达式(Nonterminal Expression) 角色: 也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式

  • 环境(Context)角色: 通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。

  • 客户端(Client) : 主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法

优缺点

  • 优点
    • 拓展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或拓展文法。
    • 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。
  • 缺点
    • 执行效率低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
    • 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
    • 可用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到

使用场景

  • 当语言的文法较为简单,且执行效率不是关键问题时

  • 当问题重复出现,且可以用一种简单的语言来进行表达时

  • 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如XML 文档解释

使用案例

装饰器模式

定义

        装饰器模式(Decorator Pattern) 也称为包装模式;是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案,属于结构型模式。装饰器模式的核心是功能拓展,使用装饰器模式可以透明且动态地拓展类的功能;

类图

角色

  • 抽象组件(Component):可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为;

  • 具体组件(ConcreteCompomponent):实现/继承Component的一个具体对象,也即被装饰对象

  • 抽象装饰器(Decorator): 通用的装饰ConcreteComponent的装饰器,其内部必然有一个属性指向Component抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个Component抽象组件,这是强制的通用行为

  • 具体装饰器(ConcreteDecorator):Decorator的具体实现类,理论上,每个ConcreteDecorator都拓展了Component对象的一种功能;

优缺点

  • 优点
    • 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象拓展功能,即插即用
    • 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
    • 装饰器完全遵守开闭原则
  • 缺点
    • 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
    • 动态装饰时,多层装饰时会更复杂

使用场景

  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类

  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时采用继承关系很难实现,而采用装饰模式却很好实现

  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时

使用案例

  • Java I/O 标准库的设计


网站公告

今日签到

点亮在社区的每一天
去签到