标签:
11个行为模式之5(责任链模式,命令模式,解释器模式,迭代器模式,中介者模式)
责任链模式
问题:
Sunny软件公司承接了某企业SCM(Supply Chain Management,供应链管理)系统的开发任务,其中包含一个采购审批子系统。该企业的采购审批是分级进行的,即根据采购金额的不同由不同层次的主管人员来审批,主任可以审批5万元以下(不包括5万元)的采购单,副董事长可以审批5万元至10万元(不包括10万元)的采购单,董事长可以审批10万元至50万元(不包括50万元)的采购单,50万元及以上的采购单就需要开董事会讨论决定。如图16-1所示:
- /采购单:请求类
- class PurchaseRequest {
- private double amount; //采购金额
- private int number; //采购单编号
- private String purpose; //采购目的
-
- public PurchaseRequest(double amount, int number, String purpose) {
- this.amount = amount;
- this.number = number;
- this.purpose = purpose;
- }
-
- public void setAmount(double amount) {
- this.amount = amount;
- }
-
- public double getAmount() {
- return this.amount;
- }
-
- public void setNumber(int number) {
- this.number = number;
- }
-
- public int getNumber() {
- return this.number;
- }
-
- public void setPurpose(String purpose) {
- this.purpose = purpose;
- }
-
- public String getPurpose() {
- return this.purpose;
- }
- }
-
- //审批者类:抽象处理者
- abstract class Approver {
- protected Approver successor; //定义后继对象
- protected String name; //审批者姓名
-
- public Approver(String name) {
- this.name = name;
- }
-
- //设置后继者
- public void setSuccessor(Approver successor) {
- this.successor = successor;
- }
-
- //抽象请求处理方法
- public abstract void processRequest(PurchaseRequest request);
- }
-
- //主任类:具体处理者
- class Director extends Approver {
- public Director(String name) {
- super(name);
- }
-
- //具体请求处理方法
- public void processRequest(PurchaseRequest request) {
- if (request.getAmount() < 50000) {
- System.out.println("主任" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
- }
- else {
- this.successor.processRequest(request); //转发请求
- }
- }
- }
-
- //副董事长类:具体处理者
- class VicePresident extends Approver {
- public VicePresident(String name) {
- super(name);
- }
-
- //具体请求处理方法
- public void processRequest(PurchaseRequest request) {
- if (request.getAmount() < 100000) {
- System.out.println("副董事长" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
- }
- else {
- this.successor.processRequest(request); //转发请求
- }
- }
- }
-
- //董事长类:具体处理者
- class President extends Approver {
- public President(String name) {
- super(name);
- }
-
- //具体请求处理方法
- public void processRequest(PurchaseRequest request) {
- if (request.getAmount() < 500000) {
- System.out.println("董事长" + this.name + "审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
- }
- else {
- this.successor.processRequest(request); //转发请求
- }
- }
- }
-
- //董事会类:具体处理者
- class Congress extends Approver {
- public Congress(String name) {
- super(name);
- }
-
- //具体请求处理方法
- public void processRequest(PurchaseRequest request) {
- System.out.println("召开董事会审批采购单:" + request.getNumber() + ",金额:" + request.getAmount() + "元,采购目的:" + request.getPurpose() + "。"); //处理请求
- }
- }
编写如下客户端测试代码:
- class Client {
- public static void main(String[] args) {
- Approver wjzhang,gyang,jguo,meeting;
- wjzhang = new Director("张无忌");
- gyang = new VicePresident("杨过");
- jguo = new President("郭靖");
- meeting = new Congress("董事会");
-
- //创建职责链
- wjzhang.setSuccessor(gyang);
- gyang.setSuccessor(jguo);
- jguo.setSuccessor(meeting);
-
- //创建采购单
- PurchaseRequest pr1 = new PurchaseRequest(45000,10001,"购买倚天剑");
- wjzhang.processRequest(pr1);
-
- PurchaseRequest pr2 = new PurchaseRequest(60000,10002,"购买《葵花宝典》");
- wjzhang.processRequest(pr2);
-
- PurchaseRequest pr3 = new PurchaseRequest(160000,10003,"购买《金刚经》");
- wjzhang.processRequest(pr3);
-
- PurchaseRequest pr4 = new PurchaseRequest(800000,10004,"购买桃花岛");
- wjzhang.processRequest(pr4);
- }
- }
命令模式
Sunny软件公司开发人员为公司内部OA系统开发了一个桌面版应用程序,该应用程序为用户提供了一系列自定义功能键,用户可以通过这些功能键来实现一些快捷操作。Sunny软件公司开发人员通过分析,发现不同的用户可能会有不同的使用习惯,在设置功能键的时候每个人都有自己的喜好,例如有的人喜欢将第一个功能键设置为“打开帮助文档”,有的人则喜欢将该功能键设置为“最小化至托盘”,为了让用户能够灵活地进行功能键的设置,开发人员提供了一个“功能键设置”窗口,该窗口界面如图2所示:
通过如图2所示界面,用户可以将功能键和相应功能绑定在一起,还可以根据需要来修改功能键的设置,而且系统在未来可能还会增加一些新的功能或功能键。
- import java.util.*;
-
- //功能键设置窗口类
- class FBSettingWindow {
- private String title; //窗口标题
- //定义一个ArrayList来存储所有功能键
- private ArrayList<FunctionButton> functionButtons = new ArrayList<FunctionButton>();
-
- public FBSettingWindow(String title) {
- this.title = title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getTitle() {
- return this.title;
- }
-
- public void addFunctionButton(FunctionButton fb) {
- functionButtons.add(fb);
- }
-
- public void removeFunctionButton(FunctionButton fb) {
- functionButtons.remove(fb);
- }
-
- //显示窗口及功能键
- public void display() {
- System.out.println("显示窗口:" + this.title);
- System.out.println("显示功能键:");
- for (Object obj : functionButtons) {
- System.out.println(((FunctionButton)obj).getName());
- }
- System.out.println("------------------------------");
- }
- }
-
- //功能键类:请求发送者
- class FunctionButton {
- private String name; //功能键名称
- private Command command; //维持一个抽象命令对象的引用
-
- public FunctionButton(String name) {
- this.name = name;
- }
-
- public String getName() {
- return this.name;
- }
-
- //为功能键注入命令
- public void setCommand(Command command) {
- this.command = command;
- }
-
- //发送请求的方法
- public void onClick() {
- System.out.print("点击功能键:");
- command.execute();
- }
- }
-
- //抽象命令类
- abstract class Command {
- public abstract void execute();
- }
-
- //帮助命令类:具体命令类
- class HelpCommand extends Command {
- private HelpHandler hhObj; //维持对请求接收者的引用
-
- public HelpCommand() {
- hhObj = new HelpHandler();
- }
-
- //命令执行方法,将调用请求接收者的业务方法
- public void execute() {
- hhObj.display();
- }
- }
-
- //最小化命令类:具体命令类
- class MinimizeCommand extends Command {
- private WindowHanlder whObj; //维持对请求接收者的引用
-
- public MinimizeCommand() {
- whObj = new WindowHanlder();
- }
-
- //命令执行方法,将调用请求接收者的业务方法
- public void execute() {
- whObj.minimize();
- }
- }
-
- //窗口处理类:请求接收者
- class WindowHanlder {
- public void minimize() {
- System.out.println("将窗口最小化至托盘!");
- }
- }
-
- //帮助文档处理类:请求接收者
- class HelpHandler {
- public void display() {
- System.out.println("显示帮助文档!");
- }
- }
为了提高系统的灵活性和可扩展性,我们将具体命令类的类名存储在配置文件中,并通过工具类XMLUtil来读取配置文件并反射生成对象,XMLUtil类的代码如下所示:
[java] view plain copy
- import javax.xml.parsers.*;
- import org.w3c.dom.*;
- import org.xml.sax.SAXException;
- import java.io.*;
-
- public class XMLUtil {
- //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象,可以通过参数的不同返回不同类名节点所对应的实例
- public static Object getBean(int i) {
- try {
- //创建文档对象
- DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = dFactory.newDocumentBuilder();
- Document doc;
- doc = builder.parse(new File("config.xml"));
-
- //获取包含类名的文本节点
- NodeList nl = doc.getElementsByTagName("className");
- Node classNode = null;
- if (0 == i) {
- classNode = nl.item(0).getFirstChild();
- }
- else {
- classNode = nl.item(1).getFirstChild();
- }
-
- String cName = classNode.getNodeValue();
-
- //通过类名生成实例对象并将其返回
- Class c = Class.forName(cName);
- Object obj = c.newInstance();
- return obj;
- }
- catch(Exception e){
- e.printStackTrace();
- return null;
- }
- }
- }
配置文件config.xml中存储了具体建造者类的类名,代码如下所示:
[java] view plain copy
- <?xml version="1.0"?>
- <config>
- <className>HelpCommand</className>
- <className>MinimizeCommand</className>
- </config>
编写如下客户端测试代码:
- class Client {
- public static void main(String args[]) {
- FBSettingWindow fbsw = new FBSettingWindow("功能键设置");
-
- FunctionButton fb1,fb2;
- fb1 = new FunctionButton("功能键1");
- fb2 = new FunctionButton("功能键1");
-
- Command command1,command2;
- //通过读取配置文件和反射生成具体命令对象
- command1 = (Command)XMLUtil.getBean(0);
- command2 = (Command)XMLUtil.getBean(1);
-
- //将命令对象注入功能键
- fb1.setCommand(command1);
- fb2.setCommand(command2);
-
- fbsw.addFunctionButton(fb1);
- fbsw.addFunctionButton(fb2);
- fbsw.display();
-
- //调用功能键的业务方法
- fb1.onClick();
- fb2.onClick();
- }
- }
解释器模式
Sunny软件公司欲为某玩具公司开发一套机器人控制程序,在该机器人控制程序中包含一些简单的英文控制指令,每一个指令对应一个表达式(expression),该表达式可以是简单表达式也可以是复合表达式,每一个简单表达式由移动方向(direction),移动方式(action)和移动距离(distance)三部分组成,其中移动方向包括上(up)、下(down)、左(left)、右(right);移动方式包括移动(move)和快速移动(run);移动距离为一个正整数。两个表达式之间可以通过与(and)连接,形成复合(composite)表达式。
用户通过对图形化的设置界面进行操作可以创建一个机器人控制指令,机器人在收到指令后将按照指令的设置进行移动,例如输入控制指令:up move 5,则“向上移动5个单位”;输入控制指令:down run 10 and left move 20,则“向下快速移动10个单位再向左移动20个单位”。
expression ::= direction action distance | composite //表达式
composite ::= expression ‘and‘ expression //复合表达式
direction ::= ‘up‘ | ‘down‘ | ‘left‘ | ‘right‘ //移动方向
action ::= ‘move‘ | ‘run‘ //移动方式
distance ::= an integer //移动距离
- //注:本实例对机器人控制指令的输出结果进行模拟,将英文指令翻译为中文指令,实际情况是调用不同的控制程序进行机器人的控制,包括对移动方向、方式和距离的控制等
- import java.util.*;
-
- //抽象表达式
- abstract class AbstractNode {
- public abstract String interpret();
- }
-
- //And解释:非终结符表达式
- class AndNode extends AbstractNode {
- private AbstractNode left; //And的左表达式
- private AbstractNode right; //And的右表达式
-
- public AndNode(AbstractNode left, AbstractNode right) {
- this.left = left;
- this.right = right;
- }
-
- //And表达式解释操作
- public String interpret() {
- return left.interpret() + "再" + right.interpret();
- }
- }
-
- //简单句子解释:非终结符表达式
- class SentenceNode extends AbstractNode {
- private AbstractNode direction;
- private AbstractNode action;
- private AbstractNode distance;
-
- public SentenceNode(AbstractNode direction,AbstractNode action,AbstractNode distance) {
- this.direction = direction;
- this.action = action;
- this.distance = distance;
- }
-
- //简单句子的解释操作
- public String interpret() {
- return direction.interpret() + action.interpret() + distance.interpret();
- }
- }
-
- //方向解释:终结符表达式
- class DirectionNode extends AbstractNode {
- private String direction;
-
- public DirectionNode(String direction) {
- this.direction = direction;
- }
-
- //方向表达式的解释操作
- public String interpret() {
- if (direction.equalsIgnoreCase("up")) {
- return "向上";
- }
- else if (direction.equalsIgnoreCase("down")) {
- return "向下";
- }
- else if (direction.equalsIgnoreCase("left")) {
- return "向左";
- }
- else if (direction.equalsIgnoreCase("right")) {
- return "向右";
- }
- else {
- return "无效指令";
- }
- }
- }
-
- //动作解释:终结符表达式
- class ActionNode extends AbstractNode {
- private String action;
-
- public ActionNode(String action) {
- this.action = action;
- }
-
- //动作(移动方式)表达式的解释操作
- public String interpret() {
- if (action.equalsIgnoreCase("move")) {
- return "移动";
- }
- else if (action.equalsIgnoreCase("run")) {
- return "快速移动";
- }
- else {
- return "无效指令";
- }
- }
- }
-
- //距离解释:终结符表达式
- class DistanceNode extends AbstractNode {
- private String distance;
-
- public DistanceNode(String distance) {
- this.distance = distance;
- }
-
- //距离表达式的解释操作
- public String interpret() {
- return this.distance;
- }
- }
-
- //指令处理类:工具类
- class InstructionHandler {
- private String instruction;
- private AbstractNode node;
-
- public void handle(String instruction) {
- AbstractNode left = null, right = null;
- AbstractNode direction = null, action = null, distance = null;
- Stack stack = new Stack(); //声明一个栈对象用于存储抽象语法树
- String[] words = instruction.split(" "); //以空格分隔指令字符串
- for (int i = 0; i < words.length; i++) {
- //本实例采用栈的方式来处理指令,如果遇到“and”,则将其后的三个单词作为三个终结符表达式连成一个简单句子SentenceNode作为“and”的右表达式,而将从栈顶弹出的表达式作为“and”的左表达式,最后将新的“and”表达式压入栈中。 if (words[i].equalsIgnoreCase("and")) {
- left = (AbstractNode)stack.pop(); //弹出栈顶表达式作为左表达式
- String word1= words[++i];
- direction = new DirectionNode(word1);
- String word2 = words[++i];
- action = new ActionNode(word2);
- String word3 = words[++i];
- distance = new DistanceNode(word3);
- right = new SentenceNode(direction,action,distance); //右表达式
- stack.push(new AndNode(left,right)); //将新表达式压入栈中
- }
- //如果是从头开始进行解释,则将前三个单词组成一个简单句子SentenceNode并将该句子压入栈中
- else {
- String word1 = words[i];
- direction = new DirectionNode(word1);
- String word2 = words[++i];
- action = new ActionNode(word2);
- String word3 = words[++i];
- distance = new DistanceNode(word3);
- left = new SentenceNode(direction,action,distance);
- stack.push(left); //将新表达式压入栈中
- }
- }
- this.node = (AbstractNode)stack.pop(); //将全部表达式从栈中弹出
- }
-
- public String output() {
- String result = node.interpret(); //解释表达式
- return result;
- }
- }
工具类InstructionHandler用于对输入指令进行处理,将输入指令分割为字符串数组,将第1个、第2个和第3个单词组合成一个句子,并存入栈中;如果发现有单词“and”,则将“and”后的第1个、第2个和第3个单词组合成一个新的句子作为“and”的右表达式,并从栈中取出原先所存句子作为左表达式,然后组合成一个And节点存入栈中。依此类推,直到整个指令解析结束。
编写如下客户端测试代码:
[java] view plain copy
- class Client {
- public static void main(String args[]) {
- String instruction = "up move 5 and down run 10 and left move 5";
- InstructionHandler handler = new InstructionHandler();
- handler.handle(instruction);
- String outString;
- outString = handler.output();
- System.out.println(outString);
- }
- }
迭代器模式
|
- //在本实例中,为了详细说明自定义迭代器的实现过程,我们没有使用JDK中内置的迭代器,事实上,JDK内置迭代器已经实现了对一个List对象的正向遍历
- import java.util.*;
-
- //抽象聚合类
- abstract class AbstractObjectList {
- protected List<Object> objects = new ArrayList<Object>();
-
- public AbstractObjectList(List objects) {
- this.objects = objects;
- }
-
- public void addObject(Object obj) {
- this.objects.add(obj);
- }
-
- public void removeObject(Object obj) {
- this.objects.remove(obj);
- }
-
- public List getObjects() {
- return this.objects;
- }
-
- //声明创建迭代器对象的抽象工厂方法
- public abstract AbstractIterator createIterator();
- }
-
- //商品数据类:具体聚合类
- class ProductList extends AbstractObjectList {
- public ProductList(List products) {
- super(products);
- }
-
- //实现创建迭代器对象的具体工厂方法
- public AbstractIterator createIterator() {
- return new ProductIterator(this);
- }
- }
-
- //抽象迭代器
- interface AbstractIterator {
- public void next(); //移至下一个元素
- public boolean isLast(); //判断是否为最后一个元素
- public void previous(); //移至上一个元素
- public boolean isFirst(); //判断是否为第一个元素
- public Object getNextItem(); //获取下一个元素
- public Object getPreviousItem(); //获取上一个元素
- }
-
- //商品迭代器:具体迭代器
- class ProductIterator implements AbstractIterator {
- private ProductList productList;
- private List products;
- private int cursor1; //定义一个游标,用于记录正向遍历的位置
- private int cursor2; //定义一个游标,用于记录逆向遍历的位置
-
- public ProductIterator(ProductList list) {
- this.productList = list;
- this.products = list.getObjects(); //获取集合对象
- cursor1 = 0; //设置正向遍历游标的初始值
- cursor2 = products.size() -1; //设置逆向遍历游标的初始值
- }
-
- public void next() {
- if(cursor1 < products.size()) {
- cursor1++;
- }
- }
-
- public boolean isLast() {
- return (cursor1 == products.size());
- }
-
- public void previous() {
- if (cursor2 > -1) {
- cursor2--;
- }
- }
-
- public boolean isFirst() {
- return (cursor2 == -1);
- }
-
- public Object getNextItem() {
- return products.get(cursor1);
- }
-
- public Object getPreviousItem() {
- return products.get(cursor2);
- }
- }
编写如下客户端测试代码:
- class Client {
- public static void main(String args[]) {
- List products = new ArrayList();
- products.add("倚天剑");
- products.add("屠龙刀");
- products.add("断肠草");
- products.add("葵花宝典");
- products.add("四十二章经");
-
- AbstractObjectList list;
- AbstractIterator iterator;
-
- list = new ProductList(products); //创建聚合对象
- iterator = list.createIterator(); //创建迭代器对象
-
- System.out.println("正向遍历:");
- while(!iterator.isLast()) {
- System.out.print(iterator.getNextItem() + ",");
- iterator.next();
- }
- System.out.println();
- System.out.println("-----------------------------");
- System.out.println("逆向遍历:");
- while(!iterator.isFirst()) {
- System.out.print(iterator.getPreviousItem() + ",");
- iterator.previous();
- }
- }
- }
使用内部类实现迭代器
- //商品数据类:具体聚合类
- class ProductList extends AbstractObjectList {
- public ProductList(List products) {
- super(products);
- }
-
- public AbstractIterator createIterator() {
- return new ProductIterator();
- }
-
- //商品迭代器:具体迭代器,内部类实现
- private class ProductIterator implements AbstractIterator {
- private int cursor1;
- private int cursor2;
-
- public ProductIterator() {
- cursor1 = 0;
- cursor2 = objects.size() -1;
- }
-
- public void next() {
- if(cursor1 < objects.size()) {
- cursor1++;
- }
- }
-
- public boolean isLast() {
- return (cursor1 == objects.size());
- }
-
- public void previous() {
- if(cursor2 > -1) {
- cursor2--;
- }
- }
-
- public boolean isFirst() {
- return (cursor2 == -1);
- }
-
- public Object getNextItem() {
- return objects.get(cursor1);
- }
-
- public Object getPreviousItem() {
- return objects.get(cursor2);
- }
- }
- }
中介者模式
Sunny软件公司欲开发一套CRM系统,其中包含一个客户信息管理模块,所设计的“客户信息管理窗口”界面效果图如图20-2所示: Sunny公司开发人员通过分析发现,在图20-2中,界面组件之间存在较为复杂的交互关系:如果删除一个客户,要在客户列表(List)中删掉对应的项,客户选择组合框(ComboBox)中客户名称也将减少一个;如果增加一个客户信息,客户列表中需增加一个客户,且组合框中也将增加一项。如果实现界面组件之间的交互是Sunny公司开发人员必须面对的一个问题?
解决:
- abstract class Mediator {
- public abstract void componentChanged(Component c);
- }
-
- //具体中介者
- class ConcreteMediator extends Mediator {
- //维持对各个同事对象的引用
- public Button addButton;
- public List list;
- public TextBox userNameTextBox;
- public ComboBox cb;
-
- //封装同事对象之间的交互
- public void componentChanged(Component c) {
- //单击按钮
- if(c == addButton) {
- System.out.println("--单击增加按钮--");
- list.update();
- cb.update();
- userNameTextBox.update();
- }
- //从列表框选择客户
- else if(c == list) {
- System.out.println("--从列表框选择客户--");
- cb.select();
- userNameTextBox.setText();
- }
- //从组合框选择客户
- else if(c == cb) {
- System.out.println("--从组合框选择客户--");
- cb.select();
- userNameTextBox.setText();
- }
- }
- }
-
- //抽象组件类:抽象同事类
- abstract class Component {
- protected Mediator mediator;
-
- public void setMediator(Mediator mediator) {
- this.mediator = mediator;
- }
-
- //转发调用
- public void changed() {
- mediator.componentChanged(this);
- }
-
- public abstract void update();
- }
-
- //按钮类:具体同事类
- class Button extends Component {
- public void update() {
- //按钮不产生交互
- }
- }
-
- //列表框类:具体同事类
- class List extends Component {
- public void update() {
- System.out.println("列表框增加一项:张无忌。");
- }
-
- public void select() {
- System.out.println("列表框选中项:小龙女。");
- }
- }
-
- //组合框类:具体同事类
- class ComboBox extends Component {
- public void update() {
- System.out.println("组合框增加一项:张无忌。");
- }
-
- public void select() {
- System.out.println("组合框选中项:小龙女。");
- }
- }
-
- //文本框类:具体同事类
- class TextBox extends Component {
- public void update() {
- System.out.println("客户信息增加成功后文本框清空。");
- }
-
- public void setText() {
- System.out.println("文本框显示:小龙女。");
- }
- }
编写如下客户端测试代码:
- class Client {
- public static void main(String args[]) {
- //定义中介者对象
- ConcreteMediator mediator;
- mediator = new ConcreteMediator();
-
- //定义同事对象
- Button addBT = new Button();
- List list = new List();
- ComboBox cb = new ComboBox();
- TextBox userNameTB = new TextBox();
-
- addBT.setMediator(mediator);
- list.setMediator(mediator);
- cb.setMediator(mediator);
- userNameTB.setMediator(mediator);
-
- mediator.addButton = addBT;
- mediator.list = list;
- mediator.cb = cb;
- mediator.userNameTextBox = userNameTB;
-
- addBT.changed();
- System.out.println("-----------------------------");
- list.changed();
- }
- }
设计模式 学习 5:
标签:
原文地址:http://blog.csdn.net/xiaoliuliu2050/article/details/51226110