23种设计模式Java版第六篇

Posted 小二玩编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23种设计模式Java版第六篇相关的知识,希望对你有一定的参考价值。

ps:本文系转载文章,阅读原文可获取源码,文章末尾有原文链接

ps:这一篇是写迭代器模式、责任链模式和命令模式

1、迭代器模式

提供一个对象来顺序访问聚合对象中的一堆数据,同时也隐藏聚合对象的内部表示;Java 中的 Collection、List、Set、Map 等就用到了迭代器模式。

迭代器模式具有以下几种角色:

(1)抽象聚合角色:创建迭代器对象的接口,一般含有添加、删除聚合对象等方法。

(2)具体聚合角色:实现抽象聚合角色,得到一个具体迭代器的对象。

(3)抽象迭代器角色:遍历聚合元素的接口或者抽象类,一般含 hasNext 等方法。

(4)具体迭代器角色:实现抽象迭代器角色中所定义的抽象方法,并保持迭代过程中的游标位置。

下面用代码举个例子:

(1)抽象迭代器角色,新建一个 MyIterator接口:

public interface MyIterator {

public void first();
public void next();
public boolean hasNext();
public boolean isFirst();
public boolean isLast();
public Object getCurrentObject();

}

(2)具体迭代器角色,新建一个 ConcreteIterator 类并实现 MyIterator接口:

public class ConcreteIterator implements MyIterator{
private int cursor;

private WeakReference<List<Object>> wr;

public ConcreteIterator(List<Object> list) {

wr = new WeakReference<List<Object>>(list);

}
@Override
public void first() {

cursor = 0;

}

@Override
public void next() {

if (cursor < size()) {
  cursor++;
}

}
private int size() {

return wr.get().size();

}

@Override
public boolean hasNext() {

if (cursor < size()) {
  return true;
}
return false;

}

@Override
public boolean isFirst() {

return cursor == 0?true:false;

}

@Override
public boolean isLast() {

return cursor == (size()-1)?true:false;

}

@Override
public Object getCurrentObject() {

return wr.get().get(cursor);

}

}

(3)抽象聚合角色,新建一个 IAggregate接口:

public interface IAggregate {
public void addObject(Object object);
public void removeObject(Object object);
public MyIterator createIterator();
}

(4)具体聚合角色,新建一个 ConcreteMyAggregate 类并实现 IAggregate接口:

public class ConcreteMyAggregate implements IAggregate{

private List<Object> list = new ArrayList<Object>();
@Override
public void addObject(Object object) {
  this.list.add(object);
}
@Override
public void removeObject(Object object) {
  this.list.remove(object);
}
@Override
public MyIterator createIterator() {
  return new ConcreteIterator(list);
}

}

(5)客户端进行调用测试:

IAggregate aggregate = new ConcreteMyAggregate();
aggregate.addObject("公众号小二玩编程");
aggregate.addObject("bb");
aggregate.addObject("cc");
aggregate.addObject("dd");
MyIterator iterator = aggregate.createIterator();
while (iterator.hasNext()) {

String msg = "遍历数据----" + iterator.getCurrentObject();
System.out.println(msg);
iterator.next();

}

日志打印如下所示:

图片

首先创建一个具体的聚合角色 ConcreteMyAggregate 实例并向上转型赋值给抽象聚合角色 IAggregate,通过聚合角色 aggregate 添加数据并创建一个具体的迭代器角色 ConcreteIterator 实例并向上转型赋值给抽象迭代器角色 MyIterator,通过迭代器模式对 iterator 的数据进行遍历。

迭代器模式可以访问一个隐藏内部表示的聚合对象的内容,遍历数据由迭代器来实现,在代码上一定程度简化了聚合类;它可以用不同方式访问一个聚合,也可以访问自定义迭代器子类的数据;运用了封装性,为不同的具体聚合类提供一个统一的接口;但是新增一个具体聚合类或者具体迭代器类,在一定程度上使用可能会复杂。

2、责任链模式

把所有请求的处理者通过前一对象的属性引用下一个对象而形成一条链,当有请求时,请求沿着这条链进行传递,直到有条件满足时就会有对象处理它。

责任链模式包含以下角色:

(1)抽象处理者角色:定义出一个处理请求的接口或者抽象类,它必须包含一个处理请求的抽象方法,最好再多写2个方法,用于设置引用下一个对象和返回下一个对象。

(2)具体处理者角色:重写抽象处理者角色处理请求的抽象方法,在该方法中进行条件筛选,符合条件就进行出现,否则将请求传给引用的下一个对象进行处理。

下面我们举个例子,某一个公司的请假流程,请假少于3天则由主管审批,请假大于等于3天小于10天就由副经理审批,请假大于等于10天小于30天由总经理审批;假设张三是主管,李四是副经理,王五是总经理,张三的领导是李四,李四的领导是王五;用代码实现一下:

(1)抽象处理者角色,新建一个抽象类 Leader:

public abstract class Leader {
protected String name;
protected Leader nextLeader;
public Leader(String name) {

super();
this.name = name;

}
public Leader getNextLeader() {

return nextLeader;

}
public void setNextLeader(Leader nextLeader) {

this.nextLeader = nextLeader;

}
public abstract void handleRequest(LeaveRequest l);
}

(2)具体处理者角色,新建一个 Director 类并继承 Leader:

public class Director extends Leader{

public Director(String name) {

super(name);

}

@Override
public void handleRequest(LeaveRequest l) {

if (l.getDay() < 3) {
  System.out.println("员工:" +l.getName() + ",请假天数:" + l.getDay() + ",理由" + l.getReason());
  System.out.println("主任:" + this.name + "审批通过");
} else {
  if (this.getNextLeader() != null) {
    this.getNextLeader().handleRequest(l);
  }
}

}

}

(3)具体处理者角色,新建一个 Manager 类并继承 Leader:

public class Manager extends Leader{

public Manager(String name) {

super(name);

}

@Override
public void handleRequest(LeaveRequest l) {

if (l.getDay() < 10) {
  System.out.println("员工:" +l.getName() + ",请假天数:" + l.getDay() + ",理由" + l.getReason());
  System.out.println("经理:" + this.name + "审批通过");
} else {
  if (this.getNextLeader() != null) {
    this.getNextLeader().handleRequest(l);
  }
}

}

}

(4)具体处理者角色,新建一个 GaneralManager 类并继承 Leader:

public class GaneralManager extends Leader{

public GaneralManager(String name) {

super(name);

}

@Override
public void handleRequest(LeaveRequest l) {

if (l.getDay() < 30) {
  System.out.println("员工:" +l.getName() + ",请假天数:" + l.getDay() + ",理由" + l.getReason());
  System.out.println("总经理:" + this.name + "审批通过");
} else {
  System.out.println("你离职吧");
}

}

}

(5)客户端进行测试调用:

    Leader a = new Director("张三");
    Leader b = new Manager("李四");
    Leader c = new GaneralManager("王五");
    a.setNextLeader(b);
    b.setNextLeader(c);
    LeaveRequest lr = new LeaveRequest("小二", 16, "娶老婆");
    LeaveRequest lr2 = new LeaveRequest("小六", 31, "去相亲");
    a.handleRequest(lr);
    a.handleRequest(lr2);

日志打印如下所示:

图片

“把所有请求的处理者通过前一对象的属性引用下一个对象而形成一条链”这句话在这个案例中是这样理解的,a 的 Leader 属性引用的是 b,b 的 Leader 属性引用的是 c;有一个员工“小二”请假16天,a 和 b 都审批不了,所以交给 c 审批,员工“小六”也是一样的道理。

责任链模式降低了对象之间的耦合度,增强了系统的可扩展性,增强了给对象指派职责的灵活性,责任链简化了对象之间的连接,分担了责任;但是它不能保证每个请求一定被处理,如果是比较长的职责链,请求的处理也许涉及多个处理对象,客户端这边要理清责任链的关系,给程序增加了一定的复杂性。

3、命令模式

将一个执行请求封装为一个对象,目的是为了发出请求的责任和执行请求的责任分开来,它们之间通过命令对象进行通信,这样就更好的对命令对象进行管理等。

命令模式包含以下几个角色:

(1)抽象命令类角色:定义一个执行命令的接口,包含了一个执行命令的抽象方法 。

(2)具体命令类角色:抽象命令类的子类也是具体实现类,它内部引用接收者角色,它的实现方法调用接收者角色执行请求的方法。

(3)接收者角色:是具体命令对象业务的真正实现者。

(4)请求者角色:请求的发送者,通过访问命令对象来执行相关请求,间接的访问接收者。

下面用代码举个例子:

(1)抽象命令类角色,写一个 Command 接口:

public interface Command {

public void execute();

}

(2)接收者角色,写一个 Receiver 类:

public class Receiver {

public void ation() {
  System.out.println("Receiver.action");
}

}

(3)具体命令类角色,写一个 ConcreteCommand 类并实现 Command 接口:

class ConcreteCommand implements Command {

private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
  this.receiver = receiver;
}
@Override
public void execute() {
  receiver.ation();
}

}

(4)请求者角色,写一个 Invoke 类:

public class Invoke {
private Command command;
public Invoke(Command command) {

this.command = command;

}
public void call() {

command.execute();

}
}

(5)客户端进行测试调用:

    Command command = new ConcreteCommand(new Receiver());
    Invoke invoke = new Invoke(command);
    invoke.call();

日志打印如下所示:

图片

在这里 ConcreteCommand 是具体命令类角色对象,它封装了接收类角色对象 Receiver;Invoke 是请求者角色对象,它封装了命令类对象 Command;当 Invoke 发出请求时(调用 call 方法),它的 call 方法调用了 Command 的 execute 方法,而 Command 的 execute 方法又调用了 Receiver 的 ation 方法。

命令模式可以降低对象之间的耦合度,新的命令也很容易地加入到系统中,可以很容易地设计一个组合命令,调用同一接口命令的方法可以实现不同的功能 ;但是很可能产生大量具体的命令类,以命令的形式进行架构、解耦请求和实现,引入了额外的类型结构,在理解上添加了一定的难度。

以上是关于23种设计模式Java版第六篇的主要内容,如果未能解决你的问题,请参考以下文章

23种设计模式Java版第一篇

23种设计模式Java版第七篇

23种设计模式Java版第八篇

23种设计模式Java版第三篇

多线程设计模式:第六篇 - ThreadLocal和Active Object模式

第六篇 设计模式之代理模式