解释器模式是一种比较难理解的模式,但如果你对Command(命令模式)和Composite(组合模式)很了解的话,你会发现其实解释器模式就是这两种的组合.为何要使用解释器模式,如何用解释器模式呢,这就是下面我们要分析的问题:
1.与Command命令模式区别
首先,让我们先区别一下它与Command(命令模式的区别)
1)解释器模式的意图在于使开发人员可以组合可执行对象,这些对象来自于对某公共操作提供各种解释的类层次结构。而命令模式的意图仅仅是一个对象中请求.
2)第二,解释器模式能否作为命令使用?当然可以,可以说它是命令模式的子模式。个体应该使用哪种设计模式,取决于你的意图。如果是期望创建组合可执行对象的工具集就可采用解释器模式,如果是采用请求封装在对象中就可采用命令模式。
2.与Composite(组合模式)区别
Interpreter模式也类似于组合模式,Composite模式通常会为单个对象和群组对象定义一个公共接口。不过,Composite模式并不要求支持不方式组织的结构,尽管该模式可以支持这些结构。而解释器模式通常会涉及不同类开的组合结构(所以说interpreter通常处于Composite模式之上)。
Interpreter模式的意图是可以按照自己定义的组合规则集合来组合可执行对象
下面就讲一个我们日常最经常碰到的实例:
如一个公司有如下层次总裁(President),老板(Boss),项目经理(Manager),员工(Employee)
一天,总裁接到一个邀请开发一套医疗管理系统,于是它就把老板叫来跟他简单说一下大概,然后就把相关事情交给老板了。
老板接到任务之后,看了看,就挑了一个精明能干的开发四部项目经理(***)去安排。四部经理拿到任务之后,立即对任务进行安排.
设计图示如下:
上面的故事中都体现着一个意思就是每个层次都是根据上级的指令进行安排任务,所以我们就定义一个接口为Command
用于接收并传递指令给相应的下一级
/**
* 命令接口
* @author Administrator
*
*/
public interface Command {
public void execute(String order);
}
总裁(president)是最上一级的人物,他收到任务之后只要把老板叫过来,并把东西丢给他,然后就是拍拍屁股出去溜达去了
/**
* 总裁
* @author Administrator
*
*/
public class President extends Human implements Command{
private Boss boss;
private String order;
public Boss callBoss(){
boss = new Boss();
return boss;
}
public void execute(String order) {
this.order = order;
boss.execute(order);
}
}
老板收到总裁的命令之后,他必须选择一个能够用途这个任务的经理,所以他要做的就是如何去找一个能干的人并把任务交给它,然后就是给他施压..
/**
* 老板
* @author Administrator
*
*/
public class Boss extends Human implements Command{
private static List<Manager> managers = new ArrayList<Manager>();
private Manager devManager;
private String order;
static{
for(int i =0;i<10;i++)
managers.add(new Manager());
}
public void serviceForPresident(){
devManager.execute(order);
}
public void execute(String order) {
//..经过分析讨论,让开发四部去开发这套系统
this.order = order;
devManager = managers.get(3);
serviceForPresident();
}
}
这聪明的老板选择项目经理之后,也就没他的事了,平时也就看看项目进展如何,然后陪总裁出去FB了。接下来的任务就是项目经理怎么去应对这些事情了。PM收到任务之后就开始对任务进行安排,对总体进行计划。他首先把客户找来,安排DBA进行数据分析,找文档撰写者开发文档,然后给领导评审。接着就是开发....然后继续交互,这样的敏捷式开发直到项目OVER啦。
public class Manager extends Human implements Command{
private static List<Employee> employees = new ArrayList<Employee>();
private Employee dba;
private Employee docs;
private List<Employee> tests;
private List<Employee> engineers;
private String order;
static{
employees.add(new Employee("dba"));
employees.add(new Employee("docs"));
for(int i =2;i<10;i++){
employees.add(new Employee("tests"));
}
for(int i =11;i<100;i++){
employees.add(new Employee("engineers"));
}
}
/**
* 分配给员工任务
*
*/
public void serviceForBoss(){
dba.execute(order);
docs.execute(order);
for(Employee test:tests)
test.execute(order);
for(Employee engineer:engineers)
engineer.execute(order);
}
public void execute(String order) {
//....老板叫同仁们开发一套医疗软件,大家努力吧
//分配具体任务需求分析,概要,DB等人员分工
this.order = order;
dba = employees.get(0);
docs= employees.get(1);
tests = employees.subList(2, 10);
engineers = employees.subList(11, 30);
serviceForBoss();
}
}
接下来就是我们这辛苦的民工们了,能做的就是响应Manager的命令进行开发
/*
*员工
*/
public class Employee extends Human implements Command{
private String role;
private String order;
public Employee(String role){
this.role = role;
}
public Employee( ){
}
public void serviceForManager(){
System.out.println("领导叫我们:"+order+",大家开始干活!"+" role:"+role);
}
public void execute(String order) {
this.order = order;
serviceForManager();
}
}
测试方法如下:
public class Test {
public static void main(String[] args) {
//总裁
President president = new President();
Boss boss = president.callBoss();//把老板叫过来让它去开发医疗系统,然后就没有总裁的事了,接下来就得老板去做了
president.execute("开发医疗系统");
}
}
解释器,语言和解析器
解释器模式意在强调解释器的工作方式,但是它并没有指定如何在运行时组合或者实例化它们。在本章,我们通过编写JAVA代码来“手工”生成新的解释器。但是创建一个新的解释器常见的方法就是使用解析器。解析器对象可以按照预定规则识别文本和分解文本结构,以便于进一步处理。比如,你可以编写一个解析器,用它创建一个对应到早期伪代码形式文本程序的机器命令解释对象。
总结:
典型的解释器模式至少包含接口的两个子类。 该类层次结构中的每个类分别实现一个公共操作,如execute(String orader)方法。尽管前面没有讨论过,但这个方法需要一个“上下文”对象,用来保存重要的状态信息。
解释器模式同时也包括boolean或者自述表达式,它也经常使用解析器来简化新的解释器对象的创建过程。如上面的例子中,DBA员工正在开发系统,另一个项目正需要一个DBA,于是就有了如下:
public class IfCommand implements Command {
protected Human human;
protected Command ifbody;
protected Command elsebody;
public IfCommand(Human human, Command ifbody, Command elsebody) {
this.human = human;
this.ifbody = ifbody;
this.elsebody = elsebody;
}
public void execute(String order) {
if (!human.isBusy()) {
ifbody.execute(order);
} else {
elsebody.execute(order);
}
}
}
为了节省资源,把首先DBA放着ifbody中,把备用DBA放入elsebody中,如果ifbody的DBA员工很忙的话,就请elsebody的DBA员工.