中介者模式和解释器模式
目录
1、中介者模式
1.1 什么是中介者模式
中介者模式就是定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。
1.2 结构图
- 中介模式共分为四种角色:
- Mediator(抽象中介者):声明具体中介者公共的方法,被抽象同事类所引用,供具体同事类适用
- ConcreteMediator(具体中介者):实现抽象中介者公共的方法,引用具体同事类完成一系列操作的封装
- Colleague(抽象同事类):声明公共方法,引用抽象中介者,供子类调用
- ConcreteColleague(具体同事类):实现公共方法,编写具体业务方法供具体中介者调用或者调用中介者中的方法。
- 具体中介者引用具体同事类完成一系列操作的封装,被抽象同事类或者具体同事类调用
1.3 实例演示
抽象中介者
public interface Mediator {
public void cook();
public void wash();
public void clean();
}
具体中介者
@NoArgsConstructor
@AllArgsConstructor
public class ConcreteMdeiator implements Mediator {
private ConcreteColleagueA concreteColleagueA;
private ConcreteColleagueB concreteColleagueB;
private ConcreteColleagueC concreteColleagueC;
@Override
public void cook() {
concreteColleagueA.cook();
concreteColleagueB.cook();
concreteColleagueC.cook();
}
@Override
public void wash() {
concreteColleagueA.wash();
concreteColleagueB.wash();
concreteColleagueC.wash();
}
@Override
public void clean() {
concreteColleagueA.clean();
concreteColleagueB.clean();
concreteColleagueC.clean();
}
}
抽象同事类
@NoArgsConstructor
@AllArgsConstructor
public abstract class Colleague {
protected Mediator mediator;
public abstract void cook();
public abstract void wash();
public abstract void clean();
}
具体同事类
@NoArgsConstructor
public class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator mediator) {
super(mediator);
}
@Override
public void cook() {
System.out.println("开始制定菜单");
this.mediator.cook();
}
@Override
public void wash() {
this.mediator.wash();
}
@Override
public void clean() {
this.mediator.clean();
}
}
public class ConcreteColleagueA extends Colleague {
@Override
public void cook() {
System.out.println("A完成了洗菜");
}
@Override
public void wash() {
System.out.println("A完成了放水");
}
@Override
public void clean() {
System.out.println("A完成了扫地");
}
}
public class ConcreteColleagueB extends Colleague {
@Override
public void cook() {
System.out.println("B完成了切菜");
}
@Override
public void wash() {
System.out.println("B完成了洗衣");
}
@Override
public void clean() {
System.out.println("B完成了拖地");
}
}
public class ConcreteColleagueC extends Colleague {
@Override
public void cook() {
System.out.println("C完成了炒菜");
}
@Override
public void wash() {
System.out.println("C完成了晾干");
}
@Override
public void clean() {
System.out.println("C完成了整理房间");
}
}
客户端
public class Client {
public static void main(String[] args) {
Mediator mediator = new ConcreteMdeiator(new ConcreteColleagueA(), new ConcreteColleagueB(), new ConcreteColleagueC());
Colleague colleague = new ConcreteColleague(mediator);
System.out.println("-----------------------");
colleague.cook();
System.out.println("-----------------------");
colleague.wash();
System.out.println("-----------------------");
colleague.clean();
}
}
1.4 小结
中介者模式优点:
- 灵活性高,因为将同事类进行了解耦,使其不必有关联性;
- 降低了类的复杂度,将一对多转化成了一对一;
中介者模式缺点:
- 中介者使用过多,会使系统变得复杂难以维护;
使用场景:
- 通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。
2、解释器模式
2.1 什么是解释器模式
解释器模式就是定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的 “语言” 是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。
2.2 结构图
- 解释器模式共分为三种角色:
- AbstractExpression(抽象表达式):终结符表达式与非终结符表达式的共同父类,声明了抽象的解释行为。
- TerminalException(终结符表达式):抽象表达式的子类,包含文法中终结符的解释操作。
- NonterminalException(非终结符表达式):抽象表达式的子类,实现了文法中非终结符的解释操作,内部包含非终结符表达式或者终结符表达式。
- Context(环境类):上下文环境
- 终结符表达式是“一句话”中包含的所有最终解释单元,非终结符表达式将一组终结符表达式连接,完成“一句话”的解释,非终结符表达式将“几句话”连接,完成一段话的解释。
2.3 实例演示
//抽象表达式
public abstract class AbstractNode {
public abstract String interpret();
}
//非终结符表达式
public class SentenceNode extends AbstractNode {
private AbstractNode actionNode;
private AbstractNode direction;
private AbstractNode distanceNode;
public SentenceNode(AbstractNode action, AbstractNode direction, AbstractNode distance) {
this.actionNode = action;
this.direction = direction;
this.distanceNode = distance;
}
public AbstractNode getActionNode() {
return actionNode;
}
public void AbstractNode(ActionNode actionNode) {
this.actionNode = actionNode;
}
public AbstractNode AbstractNode() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public AbstractNode getDistanceNode() {
return distanceNode;
}
public void setDistanceNode(DistanceNode distanceNode) {
this.distanceNode = distanceNode;
}
@Override
public String interpret() {
return direction.interpret() + actionNode.interpret() + distanceNode.interpret();
}
}
//非终结符表达式
public class AndTimeNode extends AbstractNode {
private AbstractNode left;
private AbstractNode rigth;
public AndTimeNode(AbstractNode left, AbstractNode rigth) {
this.left = left;
this.rigth = rigth;
}
public AndTimeNode() {
}
public AbstractNode getLeft() {
return left;
}
public void setLeft(AbstractNode left) {
this.left = left;
}
public AbstractNode getRigth() {
return rigth;
}
public void setRigth(AbstractNode rigth) {
this.rigth = rigth;
}
@Override
public String interpret() {
return left.interpret() + "时隔5秒后"+ rigth.interpret();
}
}
//非终结表达式
public class AndNode extends AbstractNode {
private AbstractNode left;
private AbstractNode rigth;
public AndNode(AbstractNode left, AbstractNode rigth) {
this.left = left;
this.rigth = rigth;
}
public AndNode() {
}
public AbstractNode getLeft() {
return left;
}
public void setLeft(AbstractNode left) {
this.left = left;
}
public AbstractNode getRigth() {
return rigth;
}
public void setRigth(AbstractNode rigth) {
this.rigth = rigth;
}
@Override
public String interpret() {
return left.interpret() + "再" +rigth.interpret();
}
}
/终结符表达式
public class ActionNode extends AbstractNode {
private String action;
public ActionNode() {
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public ActionNode(String action) {
this.action = action;
}
@Override
public String interpret() {
if(action.equals("move")){
return "移动";
}else if(action.equals("run")){
return "快速移动";
}else {
return "无效指令";
}
}
}
//终结符表达式
public class Direction extends AbstractNode{
private String action;
public Direction(String action) {
this.action = action;
}
public Direction() {
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@Override
public String interpret() {
if(action.equals("up")){
return "向上";
}else if(action.equals("down")){
return "向下";
}else if(action.equals("left")){
return "向左";
}else if(action.equals("rigth")){
return "向右";
}else{
return "指令不存在";
}
}
}
//终结符表达式
public class Direction extends AbstractNode{
private String action;
public Direction(String action) {
this.action = action;
}
public Direction() {
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@Override
public String interpret() {
if(action.equals("up")){
return "向上";
}else if(action.equals("down")){
return "向下";
}else if(action.equals("left")){
return "向左";
}else if(action.equals("rigth")){
return "向右";
}else{
return "指令不存在";
}
}
}
/**
* 处理类
*/
public class Handle {
private AbstractNode node;
public void handle(String instruction) {
AbstractNode left, right;
AbstractNode direction, action, distance;
Stack<AbstractNode> stack = new Stack<>();
String[] words = instruction.split(" ");
//解释句子
for (int i = 0; i < words.length; i++) {
if ("and".equals(words[i])) {
left = stack.pop();
direction = new Direction(words[++i]);
action = new ActionNode(words[++i]);
distance = new DistanceNode(words[++i]);
right = new SentenceNode(action, direction, distance);
stack.push(new AndNode(left, right));
} else if ("andATime".equals(words[i])) {
left = stack.pop();
direction = new Direction(words[++i]);
action = new ActionNode(words[++i]);
distance = new DistanceNode(words[++i]);
right = new SentenceNode(action, direction, distance);
stack.push(new AndTimeNode(left, right));
} else {
// 将第一条指令压入栈中
direction = new Direction(words[i]);
action = new ActionNode(words[++i]);
distance = new DistanceNode(words[++i]);
left = new SentenceNode(action, direction, distance);
stack.push(left);
}
}
node = stack.pop();
}
public String output() {
return node.interpret();
}
}
public class Client {
public static void main(String args[]){
String str = "up run 8 and down move 12 andATime left run 20 andATime right move 10";
Handle handle = new Handle();
handle.handle(str);
System.out.println(handle.output());
}
}
运行结果:
2.4 小结
主要优点
- 易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。
- 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。
- 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合 “开闭原则”。
主要缺点
- 对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
- 执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。
适用场景
- 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
- 一些重复出现的问题可以用一种简单的语言来进行表达。
- 一个语言的文法较为简单。
- 对执行效率要求不高。