博客详情

java设计模式(七) (原创)

作者: 朝如青丝暮成雪
发布时间:2017-09-23 10:21:34  文章分类:java编程   阅读(734)  评论(0)

设计模式中的第三类是行为型模式,共11种,分别为:

策略、模板方法、观察者、责任链、 迭代子、备忘录、状态、命令、解释器、访问者、调停者。


本篇介绍其最后3种:解释器、访问者、调停者。


Interpreter
解释器模式
1 解释器模式是类的行为模式,它给定一个语言和此语言文法表达的解释器。客户端可以使用这个解释器来解释语言中的句子。
解释器模式与编译器的发展历史有关。1972年历史上第一个被广泛使用的计算机语言--c语言诞生了,与其一同诞生的还有第一款c语言
的编译器,java语言的诞生也得益于c语言,因为它的第一款编译器就是由c开发的。
2 解释器通过一种简单的文法表达式解释一门新的语言。 我们熟知的解释型语言:javascript、 phthon、ruby、php
包括网页html、css、以及正则表达式等都是解释器模式的应用案例,就其语言本身来说就可以理解为一个强大的语法"解释器"。
3 解释器模式中涉及的角色
(1)抽象表达式角色(Express): 声明一个所有的具体表达式角色都需要实现的抽象接口,这个接口主要有一个interpret()方法,称为解释操作。
(2)终结表达式(Terminal Expression):这是一个具体角色,它实现了抽象表达式角色所要求的接口,主要是一个interpret()方法。文法中的每一个终结符都有一个具体终结表达式与之对应
(3)非终结表达式(Nonterminal Expression): 这是一个具体角色。文法中的每一条规则R=R1R2...Rn中的符号都持有一个具体的非终结符的表达式类。对于每一个R1R2...Rn中的符号都持有一个静态类型的Expression实例变量。实现解释操作,即interpret()方法。解释操作已递归方式调用所提到的代表R1R2...Rn中的个符号的实例变量。
(4)客户端角色(Client) :代表模式的客户单 ,建造一个抽象语法树 ,调用解释操作。
(5)环境上下文角色(Context): 提供解释器之外的一些全局信息,比如变量的真实量值等。


下面的例子,是运用解释器模式实现java中对布尔表达式的操作运算和求值,它源自GOF原著中的经典例子。

java示例代码:

Expression 解释器接口

package com.jelly.mypattern.interpreter;  
  
/** 
 * 解释器   接口 
 * @author jelly 
 * 解释器的文法表示 
 *  
 * Expression   ::=  Expression AND Expression 
                | Expression OR  Expression 
                | NOT Expression 
                | Variable 
                | Constant 
 * 
 */  
public interface Expression {  
    /** 
     * 解释操作  
     * @param ctx  上下文环境 
     * @return  
     */  
   public   boolean   interpret(Context ctx);  
   public  boolean  equals(Object o);  
   public int hashCode();  
   public String  toString();  
}  



Constant 布尔常量类

package com.jelly.mypattern.interpreter;  
/** 
 *  布尔 常量 
 * 例如 
 * Constant c=new Constant(true) 
 * @author jelly 
 * 
 */  
public class Constant implements  Expression {  
    
    private boolean value;  
      
    public  Constant(boolean value){  
        this.value=value;  
          
    }  
    /** 
     * 常量 解释运算 
     * 与上下文环境无关,返回其value属性值即可 
     */  
    @Override  
    public boolean interpret(Context ctx) {  
        return  this.value;  
    }  
    //重写hashCode方法  
    @Override  
    public int hashCode() {  
        return   (this.toString()).hashCode();  
    }  
    //重写 equals 方法  
    @Override  
    public boolean equals(Object o) {  
         if(o!=null&& o instanceof Constant){  
             return this.value==((Constant)o).value;  
         }  
         return false;  
    }  
    //重写toString 方法  
    @Override  
    public String toString() {  
        return new Boolean(value).toString();  
    }  
      
}  


Variable 布尔变量类

package com.jelly.mypattern.interpreter;  
  
/** 
 * 布尔   变量类 
 * @author jelly 
 * 
 */  
public class Variable implements Expression {  
  
    private String name;  
  
    public Variable(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public boolean interpret(Context ctx) {  
        return ctx.lookup(this);  
    }  
  
    @Override  
    public int hashCode() {  
         return (this.toString()).hashCode();  
    }  
  
    @Override  
    public boolean equals(Object o) {  
        if (o != null && o instanceof Variable) {  
            return this.name.equals(((Variable) o).name);  
        }  
        return false;  
  
    }  
  
    @Override  
    public String toString() {  
        return name;  
    }  
      
}  
布尔运算上下文类  Context


package com.jelly.mypattern.interpreter;  
  
import java.util.HashMap;  
import java.util.Map;  
  
/** 
 *布尔运算  上下文类  
 * @author jelly 
 * 
 */  
public class Context {  
    private  Map map=new HashMap();  
      
    public void assign(Variable var,boolean value){  
        map.put(var, new Boolean(value));  
    }  
    public boolean lookup(Variable var)throws IllegalArgumentException {  
          Boolean value= map.get(var) ;  
        if(value==null){  
             throw new IllegalArgumentException();  
        }  
        return value.booleanValue();  
    }  
   
}  


布尔运算 And


package com.jelly.mypattern.interpreter;  
  
/** 
 * 布尔运算 and 
 * @author jelly 
 * 
 */  
public class And  implements  Expression {  
    private Expression left;  
    private Expression right;  
      
    public And(Expression left,Expression right) {  
      this.left=left;  
      this.right=right;  
    }  
  
    /** 
     * 解释运算 
     */  
    @Override  
    public boolean interpret(Context ctx) {  
        return left.interpret(ctx)&&right.interpret(ctx);  
    }  
  
  
    @Override  
    public int hashCode() {  
        return (this.toString()).hashCode();  
    }  
  
  
    @Override  
    public boolean equals(Object o) {  
        if(o!=null&&o instanceof And){  
            return  this.left.equals(((And)o).left) &&  
                    this.right.equals(((And)o).right);  
        }  
        return false;  
    }  
  
    @Override  
    public String toString() {  
       return "("+left.toString()+" AND "+right.toString()+")";  
    }  
      
      
}  


布尔运算 Or

package com.jelly.mypattern.interpreter;  
  
/** 
 * 布尔运算  or 
 * @author jelly 
 * 
 */  
public class Or  implements Expression{  
    private Expression left;  
    private Expression right;  
  
      
    public Or(Expression left,Expression right) {  
       this.left=left;  
       this.right=right;  
    }  
  
    /** 
     * 解释运算 
     */  
    @Override  
    public boolean interpret(Context ctx) {  
        return left.interpret(ctx)||right.interpret(ctx);  
    }  
  
    @Override  
    public int hashCode() {  
        return (this.toString()).hashCode();  
    }  
  
    @Override  
    public boolean equals(Object o) {  
        if(o!=null&&o instanceof Or){  
            return  this.left.equals(((Or)o).left) &&  
                    this.right.equals(((Or)o).right);  
        }  
        return false;  
    }  
  
    @Override  
    public String toString() {  
        return "("+left.toString()+" OR "+right.toString()+")";  
    }  
      
}  



布尔运算 Not

package com.jelly.mypattern.interpreter;  
  
/** 
 * 布尔运算 not 
 * @author jelly 
 * 
 */  
public class Not implements Expression{  
    private Expression exp;  
  
    public Not(Expression exp) {  
          this.exp=exp;  
    }  
  
    @Override  
    public boolean interpret(Context ctx) {  
       return   !exp.interpret(ctx);  
    }  
  
    @Override  
    public int hashCode() {  
        return (this.toString()).hashCode();  
    }  
  
    @Override  
    public boolean equals(Object o) {  
        if(o!=null&&o instanceof Not){  
            return this.exp.equals(((Not)o).exp);  
        }  
          
        return false;  
    }  
  
    @Override  
    public String toString() {  
        return  "(NOT "+exp.toString()+")";  
    }  
  
      
}  


测试代码

package com.jelly.mypattern.interpreter;  
  
/**  
 * 解释器模式    客户端测试代码  
 * @author jelly  
 *  
 */  
public class InterpreterTest {  
  
    public static void main(String[] args) {  
        Context ctx=new Context();  
        //x y 表示2个布尔变量对象    c表示一个布尔常量对象  
        Variable x=new Variable("x");  
        Variable y=new Variable("y");  
        Constant c=new Constant(true);  
        //ctx 指定变量x的值为false 变量y为true,并存放到上下文对象map中  
        ctx.assign(x, false);  
        ctx.assign(y, true);  
          
        Expression  exp=new Or(new And(c,x),new And(y,new Not(x)));  
        System.out.println("执行布尔表达式运算: "+exp.toString());  
        System.out.println("运算结果为: "+exp.interpret(ctx));  
    }  
       
}  



控制台输出:

执行布尔表达式运算: ((true AND x) OR (y AND (NOT x)))
运算结果为: true








Visitor
访问者模式
1 访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可  保持不变。适用于对数据结构复杂又相对稳定的对象访问。
2 访问者模式中涉及的角色
抽象访问者角色(Visitor):声明了一个或多个访问操作,形成所有的具体元素角色必须实现的接口
具体访问者(ConcreteVisitor):实现抽象访问者角色所声明的接口。
抽象节点(Node):声明一个接受操作,接受一个访问者对象作为一个参量。
具体节点(ConcreteNode):实现抽象元素节点定义的接受操作。

3 单分派与多分派。
由于java中类、接口之间存在继承和实现的关系,多态由此而产生。java中对象的多态性体现在,在程序的运行期,java会动态判断对象的真实类型,从而准确地   调用对象真实类型的方法。(相对地,我们编译期的对象类型为静态类型)。然而java中的方法接收的参数(称为方法参量,方法接收者与方法参量统称为方法的宗量)   在方法执行期间却不能动态判断出参量的真实类型。也就是说java是"单分派"的语言(至少目前如此),  然而我们可以通过设计模式达到"双分派"的目的。这就是访  问者模式,它通过两次次"单分派"达到"双重分派"的目标,但是从本质上来说"双重分派"仍不等同于"双分派"。


访问者模式适用于访问/遍历数据结构(聚集)比较复杂,又相对稳定的对象(通常是聚集对象)

下面是java示例代码:

ObjectStructure 聚集类/模拟一个复杂的数据结构

package com.jelly.mypattern.visitor;  
  
import java.util.ArrayList;  
import java.util.Iterator;  
import java.util.List;  
  
/** 
 * 数据结构对象,模拟 一个复杂的数据结构聚集对象 
 * @author jelly 
 * 
 */  
public class ObjectStructure {  
   private List nodeList;  
  
    public ObjectStructure() {  
        nodeList=  new ArrayList();  
   }  
     
     
    public void add(Node node){  
        nodeList.add(node);  
    }  
      
    /** 
     * 运行visitor 访问者访问 自身 
     * 暴露给visitor 的访问方法 
     * @param visitor 
     */  
    public void action(Visitor visitor){  
        Iterator it=   nodeList.iterator();  
        while( it.hasNext()){  
            Node node=  it.next();  
            node.accept(visitor);  
        }  
    }  
}  




Node 抽象节点

package com.jelly.mypattern.visitor;  
  
/** 
 * 抽象节点 
 * @author jelly 
 * 
 */  
public abstract class Node {  
    
    public abstract void accept(Visitor visitor);  
}  



NodeA  具体节点A

package com.jelly.mypattern.visitor;  
  
/** 
 * 具体节点 a 
 * @author jelly 
 * 
 */  
public class NodeA  extends Node{  
      
    //访问nodeA 节点  
    public String operationA(){  
       return "nodeA 的operationA方法执行...";  
    }  
    //访问nodeB 节点  
    public String operationA2(){  
        return "nodeA 的operationA2方法执行...";  
    }  
    @Override  
    public void accept(Visitor visitor) {  
        visitor.visit(this);  
    }  
}  


NodeB 具体节点B

package com.jelly.mypattern.visitor;  
  
/** 
 * 具体节点 b 
 * @author jelly 
 * 
 */  
public class NodeB  extends Node{  
        public String operationB(){  
           return "nodeB 的operationB方法执行...";  
        }  
        public String operationB2(){  
               return "nodeB 的operationB2方法执行...";  
        }  
        @Override  
        public void accept(Visitor visitor) {  
            visitor.visit(this);  
        }  
}  



抽象访问者 Visitor

package com.jelly.mypattern.visitor;  
  
/** 
 * 抽象访问者角色 
 * @author jelly 
 * 
 */  
public interface Visitor {  
   public void visit(NodeA node);  
   public void visit(NodeB node);  
     
}  



具体访问者A  VisitorA

package com.jelly.mypattern.visitor;  
  
/** 
 * 具体访问者A 
 * @author jelly 
 * 
 */  
public class VisitorA  implements Visitor{  
  
    @Override  
    public void visit(NodeA node) {  
         System.out.println(node.operationA());  
    }  
  
    @Override  
    public void visit(NodeB node) {  
        System.out.println(node.operationB());  
    }  
  
}  



具体访问者B VisitorB

package com.jelly.mypattern.visitor;  
  
/** 
 * 具体访问者B 
 * @author jelly 
 * 
 */  
public class VisitorB implements  Visitor{  
  
    //访问nodeA 节点  
    @Override  
    public void visit(NodeA node) {  
       
        System.out.println(node.operationA());  
        System.out.println(node.operationA2());  
    }  
    //访问nodeB 节点  
    @Override  
    public void visit(NodeB node) {  
         System.out.println(node.operationB());  
         System.out.println(node.operationB2());  
    }  
  
}  



测试代码:


package com.jelly.mypattern.visitor;  
  
/** 
 * 访问者模式 测试代码 
 * @author jelly 
 * 
 */  
public class VisitorTest {  
  public static void main(String[] args) {  
       ObjectStructure  objstruct=new ObjectStructure();  
       Node node1=new NodeA();  
       Node node2=new NodeB();  
       Node node3=new NodeA();  
       Node node4=new NodeB();  
       objstruct.add(node1);  
       objstruct.add(node2);  
       objstruct.add(node3);  
       objstruct.add(node4);  
         
       Visitor visitor1=new VisitorA();  
       objstruct.action(visitor1);  
       System.out.println("---------");  
       Visitor visitor2=new VisitorB();  
       objstruct.action(visitor2);  
  }  
}  


控制台输出:

nodeA 的operationA方法执行...
nodeB 的operationB方法执行...
nodeA 的operationA方法执行...
nodeB 的operationB方法执行...
---------
nodeA 的operationA方法执行...
nodeA 的operationA2方法执行...
nodeB 的operationB方法执行...
nodeB 的operationB2方法执行...
nodeA 的operationA方法执行...
nodeA 的operationA2方法执行...
nodeB 的operationB方法执行...
nodeB 的operationB2方法执行...







Mediator
调停者模式 ,也叫中介模式
调停者模式是对象的行为模式,它包装了一系列对象相互作用的方式,使得这些对象不必显示地相互引用。从而可以使它们可以松散地耦合,保证这些相互作用可以彼此独立地变化。

如下图所示,这个示意图中有大量的对象,这些对象既会影响到别的对象,又会被别的对象所影响,因此常常叫做同事对象(Colleague)。
这些同事对象通过彼此的相互作用形成系统的行为。从图中可以看出,几乎每一个对象都需要与其他对象发生相互的作用,而这种相互作用表现为一个对象与另一个对象的直接耦合。这是一个过度耦合的系统。



通过引入调停者(Mediator),可以将系统的网状结构变为以中介为中心的星形结构。
如图所示,在这个星形状结构中,同事对象不再通过直接的联系与另一个对象发生相互作用;相反地,它通过调停者对象与另外一个对象发生作用。
调停者对象的存在保证了对象结构上的稳定,也就是说,系统的结构不会因为新对象的引入造成大量的修改工作。



调停者模式中的角色:
抽象调停者: 定义出同事对象到调停者模式对象的接口,其主要方法是一个(或多个)事件方法。在有些情况下,这个抽象对象可以省略。一般而言,这个角色由一个java抽象类或java对象实现。
具体调停者:从抽象调停者继承而来,实现类的抽象超类的事件方法。具体调停者知晓所有的具体同事类,它从一个具体同事类对象接收消息、向具体同事对象发出命令。
抽象同事角色: 定义出调停者到同事对象的结果。同事对象只知道调停者而不知道其余同事对象。
具体同事角色:具体同事类都很清楚自己在小范围内的行为,而不知道它在大范围内的目的。

java 示例代码

Mediator 抽象调停者

package com.jelly.mypattern.mediator;  
  
/** 
 * 调停者  
 * @author jelly 
 * 
 */  
public  abstract class Mediator {  
  
    public  abstract void colleagueChanged(Colleague c);  
      
}  




ConcreteMediator 具体调停者

package com.jelly.mypattern.mediator;  
  
/** 
 * 具体调停者  类 
 * @author jelly 
 * 
 */  
public class ConcreteMediator extends Mediator {  
    private ColleagueA colleagueA;  
    private ColleagueB colleagueB;  
  
    @Override  
    public void colleagueChanged(Colleague c) {  
        System.out.println(c+" 对象发生变化");  
        colleagueA.action();  
        colleagueB.action();  
    }  
    public void createConcreteMediator(){  
        colleagueA=new ColleagueA(this);  
        colleagueB=new ColleagueB(this);  
    }  
       
    public ColleagueA getColleagueA() {  
        return colleagueA;  
    }  
  
    public ColleagueB getColleagueB() {  
        return colleagueB;  
    }  
  
       
}  



抽象同事类 Colleague

package com.jelly.mypattern.mediator;  
  
/** 
 * 同事 抽象类 
 * @author jelly 
 * 
 */  
public abstract class Colleague {  
    private Mediator mediator;  
    public Colleague( Mediator mediator) {  
        this.mediator=mediator;  
    }  
    public Mediator getMediator() {  
        return mediator;  
    }  
   //抽象行动方法  
   public  abstract void action();  
     
   public void change(){  
       mediator.colleagueChanged(this);  
   }  
}  


同事类A

package com.jelly.mypattern.mediator;  
  
/** 
 * 同事类A 
 * @author jelly 
 * 
 */  
public class ColleagueA  extends Colleague{  
  
    public ColleagueA(Mediator mediator) {  
        super(mediator);  
    }  
    /** 
     * colleagueA 中的具体行动方法 
     */  
    @Override  
    public void action() {  
        System.out.println("colleagueA do something ...");  
    }  
   
}  



同事类B

package com.jelly.mypattern.mediator;  
  
  
/** 
 * 同事类B 
 * @author jelly 
 * 
 */  
public class ColleagueB  extends Colleague{  
    public ColleagueB(Mediator mediator) {  
        super(mediator);  
    }  
  
    /** 
     * colleagueB 中的具体行动方法 
     */  
    @Override  
    public void action() {  
        System.out.println("colleagueB do something ...");  
    }  
   
}  


测试代码:

package com.jelly.mypattern.mediator;  
  
/** 
 * 测试代码 
 * @author jelly 
 * 
 */  
public class MediatorTest {  
     public static void main(String[] args) {  
            ConcreteMediator mediator=new ConcreteMediator();  
            mediator.createConcreteMediator();  
             
            Colleague  c=new ColleagueA(mediator);  
            mediator.colleagueChanged(c);  
           
     }  
}  



控制台输出:

com.jelly.mypattern.mediator.ColleagueA@4be8b8 对象发生变化
colleagueA do something ...
colleagueB do something ...



至此,笔者已将GOF中的23种设计模式全部介绍完毕,然而现实中模式并非仅仅只有这些。我们天天说的MVC模式,它是一种模式,又因为它太大,贯穿于整个项目之中,所以又是一种面向对象的架构。时代变迁,模式也在不断地发展,现今各种各样的模式层出不穷,早已超出了GOF原著中的23种,它们中的绝大多数越来越多地被开发者所采纳。

然而模式万万不可被滥用,不要为用模式而使用模式。恰当的模式运用能够成就一个优秀的项目,不当的模式运用也能毁掉一个项目。在我们的开发过程中,必须要结合需求场景,分清场合地使用模式,望读者谨记!

(完)


关键字:  设计模式  java
评论信息
暂无评论
发表评论

亲,您还没有登陆,暂不能评论哦! 去 登陆 | 注册

博主信息
   
数据加载中,请稍候...
文章分类
   
数据加载中,请稍候...
阅读排行
 
数据加载中,请稍候...
评论排行
 
数据加载中,请稍候...

Copyright © 叮叮声的奶酪 版权所有
备案号:鄂ICP备17018671号-1

鄂公网安备 42011102000739号