23种设计模式之行为型(下)


关于行为型有十一种, 23种设计模式之行为型(上)分析了其中的五种。接下来这篇是剩下的六种。也是到收尾所有23种设计模式的时候了。

责任链模式(Chain of Responsebility )

定义
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

注意:责任链模式也叫职责链模式。

责任链模式是一种对象行为型模式,其主要优点如下:

  1. 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
  2. 增强了系统的可扩展性。可以根据需要增强新的请求处理类,满足开闭原则。
  3. 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态的改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
  4. 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的if或者if…else语句
  5. 责任分担,每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

缺点

  1. 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  2. 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响
  3. 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

模式的结构与实现
== 1.模式的结构==
职责链模式主要包含角色有如下:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

结构图如图1所示,客户端可按图2所示设置责任链。
在这里插入图片描述
在这里插入图片描述
代码演示

package chainOfResponsibility;

/**
 * 抽象处理者角色
 * @author myy
 *
 */
public abstract class Handler {
 private Handler next;

public Handler getNext() {
	return next;
}

public void setNext(Handler next) {
	this.next = next;
}
 public abstract void handleRequest(String request);
	
}

package chainOfResponsibility;

/**
 * 抽象处理者角色1 
 * @author myy
 *
 */
public class ConcreteHandler1 extends Handler{

	public void handleRequest(String request) {
		if(request.equals("one")) {
			System.out.println("具体处理者1负责处理该请求");
		}else {
			if(getNext()!=null) {
				getNext().handleRequest(request);
			}else {
				System.out.println("没有人处理该请求!");
			}
		}
	}

}

package chainOfResponsibility;

/**
 * 抽象处理者角色2
 * @author myy
 *
 */
public class ConcreteHandler2 extends Handler{

	public void handleRequest(String request) {
		if(request.equals("two")) {
			System.out.println("具体处理者2负责处理该请求");
		}else {
			if(getNext()!=null) {
				getNext().handleRequest(request);
			}else {
				System.out.println("没有人处理该请求");
			}
		}
	}

}

package chainOfResponsibility;

/**
 * 测试
 * @author myy
 *
 */
public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
		//组装责任链
    	Handler handler1 = new ConcreteHandler1();
    	Handler handler2 = new ConcreteHandler2();
    	handler1.setNext(handler2);
    	//提交请求
    	handler1.handleRequest("two");
	}
}

运行结果如下:
在这里插入图片描述
应用实例
用责任处理者2负责处理该请求

分析:假如规定学时请假小于或等于2天,班主任可以批准;小于或等于7天,系主任可以批准;小于或等于10天,院长可以批准;其他班情况不予批准;这个实力适合使用职责链模式实现。
首先,定义一个领导类(Leader),它是抽象处理者,包含了一个指向下一位领导的指针next和一个处理假条的抽象处理方式handleRequest(int LeaveDays);然后,定义班主任类(ClassAdviser),系主任(DepartmentHead)和院长类(Dean),它们是抽象处理者的子类,是具体处理者,必须根据自己的权利 去实现父类的handleRequest(int LeaveDays)方法,如果无权处理就将假条交给下一位具体处理者,直到最后。客户类负责创建处理链,并将假条交给链头的具体处理者(班主任)。图3所示:
在这里插入图片描述
代码演示:

package chainOfResponsibility;

/**
 * 测试
 * @author myy
 *
 */
public class LeaveApprovalTest {
public static void main(String[] args) {
	//组装责任链
	Leader tLeader1=new ClassAdviser();
	Leader tLeader2=new DepartmentHead();
	Leader tLeader3=new Dean();
//	Leader tLeader4=new DeanOfStudies();
	tLeader1.setNext(tLeader2);
	tLeader2.setNext(tLeader3);
//	tLeader3.setNext(tLeader4);
	//提交请求
	tLeader1.handleRequest(8);
}
}

package chainOfResponsibility;

/**
 * 抽象处理者:领导类
 * @author myy
 *
 */
public abstract class Leader {
	private Leader next;

	public Leader getNext() {
		return next;
	}

	public void setNext(Leader next) {
		this.next = next;
	}
	//处理请求的方法
	public abstract void handleRequest(int LeaveDays);
	
}

package chainOfResponsibility;

/**
 * 具体处理者1:班主任类
 * @author myy
 *
 */
public class ClassAdviser extends Leader{

	public void handleRequest(int LeaveDays) {
		if(LeaveDays <= 2) {
			System.out.println("班主任批准你请假"+ LeaveDays +"天");
		}else {
			if(getNext() != null) {
				getNext().handleRequest(LeaveDays);
			}else {
				System.out.println("请假天数太多,没有人批准该假条");
			}
		}
	}

	
}

package chainOfResponsibility;

/**
 * 具体处理者2:系主任类
 * @author myy
 *
 */
public class DepartmentHead extends Leader{

	public void handleRequest(int LeaveDays) {
		if(LeaveDays <= 7) {
			System.out.println("系主任批准你请假"+ LeaveDays +"天");
		}else {
			if(getNext() !=null) {
				getNext().handleRequest(LeaveDays);
			}else {
				System.out.println("请假天数太多,没有人批准该假条");
			}
		}
	}

}

package chainOfResponsibility;

/**
 * 具体处理者3:院长类
 * @author myy
 *
 */
public class Dean extends Leader{

	public void handleRequest(int LeaveDays) {
		if(LeaveDays <= 10) {
			System.out.println("院长批准您请假"+ LeaveDays +"天");
		}else {
			if(getNext() != null) {
				getNext().handleRequest(LeaveDays);
			}else {
				System.out.println("请假天数太多,没有人批准该请假条");
			}
		}
		
	}

}

package chainOfResponsibility;

public class DeanOfStudies extends Leader{

	public void handleRequest(int LeaveDays) {
		if(LeaveDays <= 20) {
			System.out.println("教务处长批准你请假"+LeaveDays+"天");
		}else {
			if(getNext()!=null) {
				getNext().handleRequest(LeaveDays);
			}else {
				System.out.println("请假天数太多,没有人批准该假条");
			}
		}
	}

}

运行结果如下:
在这里插入图片描述
应用场景

  1. 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定
  2. 可动态指定一组对象处理请求,或添加新的处理者
  3. 在不明确指定请求处理者的情况下,向多个处理者中一个提交请求

模式的扩展
职责链模式存在以下两种情况:

  1. 纯的职责链模式:一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任);把责任推给下家处理。
  2. 不纯的职责链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被如何接收端对象所接收。

命令模式(Command)

定义
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储,传递,调用,增加与管理。
优点

  1. 降低系统的耦合度。命令模式将调用操作的对象与实现该操作的对象解耦。
  2. 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
  3. 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
  4. 方便实现 Undo 和 Redo 操作。命令模式可以与后面的备忘录模式结合,实现命令撤销与恢复。
    缺点
    可以产生大量具体命令类。因为针对每一个具体操作都需要设计一个具体命令类,这将增加系统的复杂性。

可以将系统中的相关操作抽象成命令,使调用者与实现者相关分离

结构

  1. 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法execute()。
  2. 具体命令(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  3. 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  4. 调用者/请求者(lnvoker)角色:是请求的发送者,它通常拥有很多命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

如下图:
在这里插入图片描述
代码演示:

package command;

public class CommandPattern {
	public static void main(String[] args) {
		Command command = new ConcreteCommand();
		Invoker invoker = new Invoker(command);
		System.out.println("客户访问调用者的call()方法。");
		invoker.call();
	}
}

package command;

/**
 * 调用
 * @author myy
 *
 */
public class Invoker {
  private Command command;

public Invoker(Command command) {
	this.command = command;
}

public Command getCommand() {
	return command;
}

public void setCommand(Command command) {
	this.command = command;
}
 
public void call() {
	System.out.println("调用执行命令command..");
	command.execute();
}
}

package command;

/**
 * 抽象命令
 * @author myy
 *
 */
public interface Command {
 public abstract void execute();
}

package command;

/**
 * 具体命令
 * @author myy
 *
 */
public class ConcreteCommand implements Command{

	private Receiver receiver;
	public ConcreteCommand() {
		receiver=new Receiver();
	}
	public void execute() {
      receiver.action();		
	}

}

package command;

/**
 * 接收者
 * @author myy
 *
 */
public class Receiver {
	public void action() {
	System.out.println("接收者action()方法被调用。");
	}
}

运行结果:
在这里插入图片描述
应用场景

  1. 当系统需要将请求调用者与请求接收者解耦时,命令模式使得调用者不直接交互。
  2. 当系统需要随机请求命令或经常增加或删除命令时,命令模式比较方便实现这些功能。
  3. 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
  4. 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。

扩展
在软件开发中,有时将命令模式与前面学的模式联合使用,这就构成了宏命令模式,也叫组合命令模式。宏命令包括一组命令,它充当了具体命令与调用者的双重角色,执行它时将递归调用它所包含的所有命令,其具体结果如下:
在这里插入图片描述
代码演示:

package command;

public class CompositeCommandPattern {
 public static void main(String[] args) {
	AbstractCommand cmd1 = new ConcreteCommand1();
	AbstractCommand cmd2 = new ConcreteCommand2();
	CompositeInvoker ir = new CompositeInvoker();
	ir.add(cmd1);
	ir.add(cmd2);
	System.out.println("客户访问调用者的execute()方法");
	ir.execute();
}
}

package command;

/**
 * 树叶构件:具体命令1
 * @author myy
 *
 */
public class ConcreteCommand1 implements AbstractCommand{

	private CompositeReceiver receiver;
	public ConcreteCommand1() {
		receiver=new CompositeReceiver();
	}
	
	public void execute() {
		receiver.action1();
	}

}

package command;

/**
 * 抽象命令
 * @author myy
 *
 */
public interface AbstractCommand {
	public abstract void execute();
}

package command;

/**
 * 接收者
 * @author myy
 *
 */
public class CompositeReceiver {
  public void action1() {
	  System.out.println("接收者action1()方法被调用");
  }
  public void action2() {
	  System.out.println("接收者的action2()方法被调用");
  }
  
}

package command;

/**
 * 树叶构件:具体命令2
 * @author myy
 *
 */
public class ConcreteCommand2 implements AbstractCommand{

	private CompositeReceiver receiver;
	public ConcreteCommand2() {
     receiver = new CompositeReceiver();
	}
	public void execute() {
		receiver.action2();
	}

}

package command;

import java.util.ArrayList;

/**
 * 树枝构件:调用者
 * @author myy
 *
 */
public class CompositeInvoker implements AbstractCommand{

	private ArrayList<AbstractCommand> children = new ArrayList<AbstractCommand>();
	
	public void add(AbstractCommand c) {
		children.add(c);
	}
	
	public void remove(AbstractCommand c) {
		children.remove(c);
	}
	
	public AbstractCommand getChild(int i) {
		return children.get(i);
	}
	
	public void execute() {
		for (Object obj : children) {
			((AbstractCommand)obj).execute();
		}
	}

}

运行结果:
在这里插入图片描述

命令模式还可以同备忘录模式(Memento)组合使用,这样就变成了可撤销的命令模式

备忘录模式(Memento)

定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

备忘录模式时一种对象行为型模式

优点

  • 提供了一种可以恢复状态的机制。当客户需要时能够方便地将数据恢复到某个老师的状态
  • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
  • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则

缺点
资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源

备忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类

结构
主要角色有:

  1. 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  2. 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  3. 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能备忘录的内容进行访问与修改。

结构如下图所示:
在这里插入图片描述
代码演示:

package memento;

public class MementoPattern {

	public static void main(String[] args) {
		Originator or = new Originator();
		Caretaker cr = new Caretaker();
		or.setState("S0");
		System.out.println("初始状态:"+or.getState());
		cr.setMemento(or.createMemento());//保存状态
		or.setState("S1");
		System.out.println("新的状态:"+or.getState());
		or.restoreMemento(cr.getMemento());//恢复状态
		System.out.println("恢复状态:"+or.getState());
	}
}

package memento;

/**
 * 备忘录
 * @author myy
 *
 */
public class Memento {
 private String state;
 public Memento(String state) {
	 this.state=state;
 }
public String getState() {
	return state;
}
public void setState(String state) {
	this.state = state;
}
 
}

package memento;

/**
 * 发起人
 * @author myy
 *
 */
public class Originator {
  private String state;
  public void setState(String state)
  { 
      this.state=state; 
  }
  public String getState()
  { 
      return state; 
  }
  public Memento createMemento()
  { 
      return new Memento(state); 
  } 
  public void restoreMemento(Memento m)
  { 
      this.setState(m.getState()); 
  } 
}

package memento;

/**
 * 管理者
 * @author myy
 *
 */
public class Caretaker {
 private Memento memento;

public Memento getMemento() {
	return memento;
}

public void setMemento(Memento memento) {
	this.memento = memento;
}
 
}

运行结果:
在这里插入图片描述

解释器模式(Interpreter)

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

“文法”指语言的语法规则,而“句子”是语言集中的元素。例如,汉语中的句子有很多,“我是中国人”是其中的一个句子,可以用一棵语法数来直观地描述语言中的句子

解释器模式是一种行为型模式
优点

  1. 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
  2. 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。

缺点

  1. 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调式过程也比较麻烦。
  2. 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
  3. 可应用的场景比较少。在软件开发中,需要定义语言文法语言文法的应用实例非常少,所以这种模式很少被使用到。

模式结构与实现
解释器模式常用于对简单语言的编译或分析实例中,为了掌握好它的结构与实现,必须先了解编译原理中的“文法,句子,语法树”等相关概念。

1.文法
文法是用于描述语言的语法结构的形式规则。没有规矩不成方圆,例如,有些人认为完美爱情的准则是“相互吸引、感情专一、任何一方都没有恋爱经历”,虽然最后一条准则较苛刻,但任何事情都要有规则,语言也一样,不管它是机器语言还是自然语言,都有它自己的文法规则。例如,中文中的“句子”的文法如下。

〈句子〉::=〈主语〉〈谓语〉〈宾语〉
〈主语〉::=〈代词〉|〈名词〉
〈谓语〉::=〈动词〉
〈宾语〉::=〈代词〉|〈名词〉
〈代词〉你|我|他
〈名词〉7大学生I筱霞I英语
〈动词〉::=是|学习

注:这里的符号“::=”表示“定义为”的意思,用“〈”和“〉”括住的是非终结符,没有括住的是终结符。

2.句子
句子是语言的基本单位,是语言集中的一个元素,它由终结符构成,能由"文法"推导出.例如,上述文法可以推出"我是大学生",所以它是句子

语法树
语法树是句子结构的一种树型表示,它代表了句子的推导结果,它有利于理解句子语法结构的层次.

如下"我是大学生"的语法树:
在这里插入图片描述
由上基础知识,更好理解解释器模式.

结构
主要角色:

  1. 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
  2. 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
  3. 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
  4. 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
  5. 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

结构图如下所示:
在这里插入图片描述
解释器模式实现的关键是定义文法规则、设计终结符类与非终结符类、画出结构图,必要时构建语法树,其代码结构如下:

package Interpreter;

/**
 * 抽象表达式类
 * @author myy
 *
 */
public interface AbstractExpression {
  public Object interpret(String info);//解释方法
}

package Interpreter;

/**
 * 终结符表达式类
 * @author myy
 *
 */
public class TerminalExpression implements AbstractExpression{

	public Object interpret(String info) {
		return null;
		 //对终结符表达式的处理
	}

}

package Interpreter;

/**
 * 非终结符表达式类
 * @author myy
 *
 */
public class NonterminalExpression implements AbstractExpression{

	 private AbstractExpression exp1;
	 private AbstractExpression exp2;
	public Object interpret(String info) {
		//非对终结符表达式的处理
		return null;
	}

}

package Interpreter;

/**
 * 环境类
 * @author myy
 *
 */
public class Context {
  private AbstractExpression exp;
  public Context() {
	//数据初始化
  }
  public void operation(String info)
  {
      //调用相关表达式类的解释方法
  }
}

应用实例
案例:用解释器模式设计一个“xxx”公交车卡的读卡器程序

说明:假如"xxx"公交车读卡器可以判断乘客的身份,如果是“A地区”或“B地区”的“老人”,“妇女”,“儿童”就可以免费乘车,其他人员乘车一次扣2元。

分析:本实例用“解释器模式”设计比较适合,首先设计其文法规则如下。

<expression> ::= <city>的<person>
<city> ::= A地区|B地区
<person> ::= 老人|妇女|儿童

则,根据文法规则按以下步骤设计公交车卡的读卡器程序的类图。

  • 定义一个抽象表达式(Expression)接口,它包含了解释方法interpre(String info).
  • 定义一个终结符表达式(Terminal Expression)类,它用集合(Set)类来保存满足条件的城市或人,并实现抽象表达式接口中的解释方法interpret(String info),用来判断被分析的字符串是否集合中的终结符。
  • 定义一个非终结符表达式(AndExpressicm)类,它也是抽象表达式的子类,它包含满足条件的城市的终结符表达式对象和满足条件的人员的终结符表达式对象,并实现interpret(String info)方法,用来判断被分析的字符串是否满足条件的城市中的满足条件人员。
  • 最后,定义一个环境(Context)类,它包含解释器需要的数据,完成对终结符表达式的初始化,并定义一个方法freeRide(String info)调用表达式对象的解释方法来对被分析的字符串进行解释。
    结构图如下,所示:
    在这里插入图片描述
package Interpreter;

/**
 * 文法规则
 * <expression> ::= <city>的<person>
 * <city> ::= A地区|B地区
 * <person> ::= 老人|妇女|儿童
 * @author myy
 *
 */
public class InterpreterPatternDemo {
public static void main(String[] args) {
	Context bus = new Context();
	bus.freeRide("A地区的老人");
    bus.freeRide("A地区的年轻人");
    bus.freeRide("B地区的妇女");
    bus.freeRide("B地区的儿童");
}
}

package Interpreter;

/**
 * 抽象表达式类
 * @author myy
 *
 */
public interface Expression {
  public boolean interpret(String info);
}

package Interpreter;

import java.util.HashSet;
import java.util.Set;

/**
 * 终结符表达式类
 * @author myy
 *
 */
public class TerminalExpression implements Expression{

	private Set<String> set = new HashSet<String>();
	public TerminalExpression(String[] data) {
		for (int i = 0; i < data.length; i++)set.add(data[i]);
		
	}
	public boolean interpret(String info) {
		if(set.contains(info)) {
			return true;
		}
		return false;
	}


}

package Interpreter;

/**
 * 非终结符表达式
 * @author myy
 *
 */
public class AndExpression implements Expression{

	private Expression city = null;
	private Expression person = null;
	public AndExpression(Expression city,Expression person) {
		this.city=city;
		this.person=person;
	}
	
	public boolean interpret(String info) {
		String s[]=info.split("的");
		return city.interpret(s[0])&&person.interpret(s[1]);
	}

}

package Interpreter;

/**
 * 环境类
 * @author myy
 *
 */
public class Context {

  private String[] citys= {"A地区","B地区"};
  private String[] persons= {"老人","妇女","儿童"};
  private Expression cityPerson;
  
  public Context() {
	//数据初始化
	  Expression city = new TerminalExpression(citys);
	  Expression person=new TerminalExpression(persons);
	  cityPerson = new AndExpression(city, person);
  }
  public void freeRide(String info)
  {
      //调用相关表达式类的解释方法
	  boolean ok = cityPerson.interpret(info);
	  if(ok) System.out.println("您是"+info+",您本次乘车免费");
	  else System.out.println(info+",您不是免费人员,本次乘车扣费2元");
  }
}

运行结果:
在这里插入图片描述
应用场景

  1. 当语言的文法较为简单,且执行效率不是关键问题时。
  2. 当问题重复出现,且可以用一种简单的语言来进行表达时。
  3. 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候。

注意:解释器模式在实际的软件开发中使用比较少,因为它会引起效率,性能以及维护等问题。如果碰到对表达式的解释,在Java中可以用Expression4J或Jep等来设计。

迭代器模式(Iterator)

定义
提供了一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为型模式。

优点

  1. 访问一个聚合对象的内容而无须暴露它的内部表示
  2. 遍历任务交由迭代器完成,者简化了聚合类
  3. 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历
  4. 增加新的聚合类和迭代器都很方便,无须修改原有的代码
  5. 封装性良好,为遍历不同的聚合结构提供一个统一的接口

缺点
增加了类的个数,这正在一定程度上增加了系统的复杂性

迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据.

结构
主要角色:

  1. 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
  2. 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例
  3. 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包括hasNaxt()、first()、next()等方法
  4. 具体迭代器(ConcreteIterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置

如下图所示:
在这里插入图片描述
代码演示:

package iterator;

import java.util.*;

public class IteratorPattern {
  public static void main(String[] args) {
	Aggregate aggregate = new ConcreteAggregate();
	aggregate.add("湖南大学");
	aggregate.add("理工大学");
	aggregate.add("中南大学");
	System.out.println("聚合的内容有:");
	  Iterator it=aggregate.getIterator(); 
	 while(it.hasNext())
     { 
         Object ob=it.next(); 
         System.out.print(ob.toString()+"\t"); 
     }
     Object ob=it.first();
     System.out.println("\nFirst:"+ob.toString());
}
}

package iterator;


/**
 * 抽象聚合
 * @author myy
 *
 */
public interface Aggregate {
	public void add(Object obj); 
    public void remove(Object obj); 
    public Iterator getIterator(); 
}

package iterator;

import java.util.*;

/**
 * 具体聚合
 * @author myy
 *
 */
public class ConcreteAggregate implements Aggregate{

	private List<Object> list = new ArrayList<Object>();
	public void add(Object obj) {
		list.add(obj);
	}

	public void remove(Object obj) {
		list.remove(obj);
	}
     
	public Iterator getIterator() {
		return (new ConcreteIterator(list));
	}

}

package iterator;

/**
 * 抽象迭代器
 * @author myy
 *
 */
public interface Iterator {
   Object first();
   Object next();
   boolean hasNext();
}

package iterator;

import java.util.List;

public class ConcreteIterator implements Iterator{

	private List<Object> list=null; 
    private int index=-1; 
    public ConcreteIterator(List<Object> list)
    { 
        this.list=list; 
    } 
    public boolean hasNext()
    { 
        if(index<list.size()-1)
        { 
            return true;
        }
        else
        {
            return false;
        }
    }
    public Object first()
    {
        index=0;
        Object obj=list.get(index);;
        return obj;
    }
    public Object next()
    { 
        Object obj=null; 
        if(this.hasNext())
        { 
            obj=list.get(++index); 
        } 
        return obj; 
    }   
}

运行结果:
在这里插入图片描述

应用场景

  1. 当需要为聚合对象提供多种遍历方式时
  2. 当需要为遍历不同的聚合结构提供一个统一的接口时
  3. 当访问一个聚合对象的内容而无须暴露其内部细节的表示时

中介者模式(Mediator)

定义
定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地该变它们之间的交互.中介者模式又叫调停模式,它们是迪米特法则的典型应用

中介者模式是一种对象行为型模式

优点

  1. 降低了对象之间的耦合性,使得对象易于独立地被复用
  2. 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展

缺点
当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护

中介者模式实现的关键是找出“中介者”

结构
主要角色:

  1. 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法
  2. 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个List来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色
  3. 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能
  4. 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互

如下图所示:
在这里插入图片描述
代码演示:

package mediator;

public class MediatorPattern {
public static void main(String[] args) {
	Mediator mediator = new ConcreteMediator();
	Colleague c1 = new ConcreteColleague1();
	Colleague c2 = new ConcreteColleague2();
	mediator.register(c1);
	mediator.register(c2);
	c1.send();
	System.out.println("------");
	c2.send();
}
}

package mediator;

/**
 * 抽象中介者
 * @author myy
 *
 */
public abstract class Mediator {
 public abstract void register(Colleague colleague);
 public abstract void relay(Colleague cl); //转发
 
}

package mediator;

import java.util.ArrayList;
import java.util.List;

/**
 * 具体中介者
 * @author myy
 *
 */
public class ConcreteMediator extends Mediator{

	private List<Colleague> colleagues = new ArrayList<Colleague>();
	public void register(Colleague colleague) {
		if(!colleagues.contains(colleague)) {
			colleagues.add(colleague);
			colleague.setMedium(this);
		}
	}

	public void relay(Colleague cl) {
		for (Colleague co : colleagues) {
			if(!co.equals(cl)) {
				 ((Colleague)co).receive();
			}
		}
	}

}

package mediator;

/**
 * 抽象同事类
 * @author myy
 *
 */
public abstract class Colleague {
  protected Mediator mediator;
  public void setMedium(Mediator mediator) {
	  this.mediator = mediator;
  }
  public abstract void receive();
  public abstract void send();
}

package mediator;

/**
 * 具体同事类
 * @author myy
 *
 */
public class ConcreteColleague1 extends Colleague{

	public void receive() {
		System.out.println("具体同事类1收到请求");
	}

	public void send() {
		System.out.println("具体同事类1收到请求");
		mediator.relay(this);//请中介转发
	}

}

package mediator;

/**
 * 具体同事类
 * @author myy
 *
 */
public class ConcreteColleague2 extends Colleague{

	public void receive() {
		System.out.println("具体同事类2收到请求");
	}

	public void send() {
		System.out.println("具体同事类2收到请求");
		mediator.relay(this);//请中介者转发
	}

}

运行结果:
在这里插入图片描述
应用场景

  1. 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时.
  2. 当想创建一个运行多个类之间的对象,又不想生产新的子类时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值