三、中介者模式在源码中的应用
首先来看JDK中的Timer类 ,打开Timer的结构我们发现Timer类中有很多的schedule() 重载方法,如下图:
我们任意点开其中一个方法,发现所有方法最终都是调用了私有的sched()方法,我们来看 —下它的源码: ::
public class Timer { public void schedule(TimerTask task, long delay, long period) { if (delay < 0) throw new IllegalArgumentException("Negative delay."); if (period <= 0) throw new IllegalArgumentException("Non-positive period."); sched(task, System.currentTimeMillis()+delay, -period); } private void sched(TimerTask task, long time, long period) { if (time < 0) throw new IllegalArgumentException("Illegal execution time."); // Constrain value of period sufficiently to prevent numeric // overflow while still being effectively infinitely large. if (Math.abs(period) > (Long.MAX_VALUE >> 1)) period >>= 1; synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } queue.add(task); if (queue.getMin() == task) queue.notify(); } } }
而且,我们发现,不管是什么样的任务都被加入到一个队列中顺序执行。我们把这个队列中 的所有对象称之为"同事”。同事之间通信都是通过Timer来协调完成的,Timer就承担了中 介者的角色。
四、解释器模式
解释器模式(Interpreter Pattern) 是指给定一门语言, 定义它的语法的一种表示, 并定义一个解释器,该解释器使用该表示来解释语言中的句子。是一种按照规定的语法进行解析的模式,属于行为型模式。
就比如编译器可以将源码编译解释为机器码, 让CPU能进行识别并运行。解释器模式的作用其实与编译器一样,都是将一些固定的语法进行解释,构建出一个解释句子的解释器。简单理解,解释器是一个简单语法分析工具,它可以识别句子语义,分离终结符号和非
终结符号,提取出需要的信息,让我们能针对不同的信息做出相应的处理。其核心思想是识别语法,构建解释。
解释器模式的应用场景:
其实我们每天都生活在解释器模式中,我们平时所听到的音乐都可以通过简谱记录下来;还有战争年代发明的摩尔斯电码(又译为摩斯密码, Morsecode) , 其实也是一种解释器。我们的程序中,如果存在一种特定类型的问题,该类型问题涉及多个不同实例,但是具备固定语法描述,那么可以使用解释器模式对该类型问题进行解释,分离出需要的信息,根据获取的信息做出相应的处理。简而言之,对于一些固定语法构建一个解释句子的解释器。解释器模式适用于以下应用场景:
一些重复出现的问题可以用一种简单的语言来进行表达;
一个简单语法需要解释的场景。
解释器模式主要包含四种角色:
1.抽象表达式(Expression) :负责定义一个解释方法interpret, 交由具体子类进行具体解释;
2.终结符表达式(Terminal Expression) :实现文法中与终结符有关的解释操作。文法中的每一个终结符都有一个具体终结表达式与之相对应,比如公式R=R1+R2,R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1,R2);
3.非终结符表达式(Nonterminal Expression) :实现文法中与非终结符有关的解释操作。文法中的每条规则都对应于一个非终结符表达式。非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中, “+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式;
4.上下文环境类(Context) :包含解释器之外的全局信息。它的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,给R1赋值100,给R2赋值200,这些信息需要存放到环境中。
五、解释器模式的实例
下面我们用解释器模式来实现一个数学表达式计算器,包含加减乘除运算。首先定义抽象表达式角色IArithmeticInterpreter接口:
public interface IArithmeticInterpreter { int interpret(); }
创建终结表达式角色AbstractInterpreter抽象类:
public abstract class AbstractInterpreter implements IArithmeticInterpreter { protected IArithmeticInterpreter left; protected IArithmeticInterpreter right; public AbstractInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { this.left = left; this.right = right; } }
分别创建非终结表达式角色加、减、乘、除解释器:
//加 public class AddInterpreter extends AbstractInterpreter { public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); } public int interpret() { return this.left.interpret() + this.right.interpret(); } } //减 public class SubInterpreter extends AbstractInterpreter { public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); } public int interpret() { return this.left.interpret() - this.right.interpret(); } } //乘 public class MultiInterpreter extends AbstractInterpreter { public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){ super(left,right); } public int interpret() { return this.left.interpret() * this.right.interpret(); } } //除 public class DivInterpreter extends AbstractInterpreter { public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){ super(left,right); } public int interpret() { return this.left.interpret() / this.right.interpret(); } }