设计模式 学习 5()
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
functionButtons = new ArrayList (); - 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("显示帮助文档!");
- }
- }
[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;
- }
- }
- }
[java] view plain copy
HelpCommand MinimizeCommand
- 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个单位”;输入控制指令:downrun 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 //移动距离
编写如下客户端测试代码: [java] view plain copy
迭代器模式 |
- //在本实例中,为了详细说明自定义迭代器的实现过程,我们没有使用JDK中内置的迭代器,事实上,JDK内置迭代器已经实现了对一个List对象的正向遍历
- import java.util.*;
- //抽象聚合类
- abstract class AbstractObjectList {
- protected List
- 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();
- }
- }
推荐阅读
- 由浅入深理解AOP
- 继续努力,自主学习家庭Day135(20181015)
- python学习之|python学习之 实现QQ自动发送消息
- 一起来学习C语言的字符串转换函数
- 定制一套英文学习方案
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- 《深度倾听》第5天──「RIA学习力」便签输出第16期
- 如何更好的去学习
- 【韩语学习】(韩语随堂笔记整理)
- 焦点学习田源分享第267天《来访》