代码Github连接 :https://github.com/tangbi123/Tab-Design-Pattern
Visitor模式
Visitor模式中,数据结构与处理被分离开来。
我们编写“访问者”的类来访问数据结构中的元素,并把对各元素的处理交给访问者类。这样,当需要增加新的处理时,我们只需要修改或编写新的访问者,然后让数据结构可以接受访问者的访问即可。
1、示例
代码清单
1)Visitor
public abstract class Visitor {
public abstract void visit(File file);
public abstract void visit(Directory directory);
}
2)Element
public interface Element {
public abstract void accept(Visitor v);
}
3)FileThredmentException
public class FileTreatmemtException extends RuntimeException {
public FileTreatmemtException() {
}
public FileTreatmemtException(String message) {
super(message);
}
}
4)Entry
public abstract class Entry implements Element{
public abstract String getName();
public abstract int getSize();
public Entry add(Entry entry) throws FileTreatmemtException
{
throw new FileTreatmemtException();
}
public Iterator iterator() throws FileTreatmemtException{
throw new FileTreatmemtException();
}
public String toString(){
return getName() + "(" + getSize() + ")";
}
}
5)File
public class File extends Entry{
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return name;
}
@Override
public int getSize() {
return size;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
6)Directory
public class Directory extends Entry {
private String name;
private ArrayList directory = new ArrayList();
public Directory(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public int getSize() {
int size = 0;
Iterator it = directory.iterator();
while(it.hasNext()){
Entry entry = (Entry) it.next();
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry){
directory.add(entry);
return this;
}
public Iterator iterator(){
return directory.iterator();
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
7)ListVisitor
public class ListVisitor extends Visitor{
private String currentDir = "";
@Override
public void visit(File file) {
System.out.println(currentDir + "/" + file);
}
@Override
public void visit(Directory directory) {
System.out.println(currentDir + "/" + directory);
String saveDir = currentDir;
currentDir = currentDir + "/" + directory.getName();
Iterator it = directory.iterator();
while(it.hasNext()){
Entry entry = (Entry)it.next();
//用 本visitor访问 entry
entry.accept(this);
}
currentDir = saveDir;
}
}
8)Main
public class VisitorMain {
public static void main(String[] args) {
System.out.println("Making root entries...");
Directory rootDir = new Directory("root");
Directory binDir = new Directory("bin");
Directory tmpDir = new Directory("tmp");
Directory userDir = new Directory("user");
rootDir.add(binDir);
rootDir.add(tmpDir);
rootDir.add(userDir);
binDir.add(new File("vi", 10000));
binDir.add(new File("latex", 20000));
rootDir.accept(new ListVisitor());
}
}
时序图
2、角色
1)Visitor(访问者) =》 visitor
负责对数据结构中的每个具体元素, 声明一个用于访问 xxxx的visit(xxxx)的方法。 visit(xxxx)用于处理xxxx的方法,负责实现该方法的是ConcretVisitor。
2)ConcreteVisitor(具体访问者) =》 ListVisitor
负责实现Visitor角色所定义的接口(API)。实现所有的visit(xxxx)方法,即实现处理每个ConcreteElement角色。
3)Element(元素)
Element角色表示Visitor角色访问的对象。声明了接受访问者accept方法,参数是Visitor角色。
4)ConcreteElement =》 File、Directory
负责实现Element角色所定义的接口(API)。
5)ObjectStructure(对象结构) =》Directory
负责处理Element角色的集合,ConcreteVisistor角色为美俄个Element角色都准备了处理方法。
3、思路要点
双重分发
element.accept(Visitor);
visitor.visit(element);
他们是相反的关系,element接受visitor,而visitor又访问element。
ConcreteElement和ConcreteVisitor这两个角色共同决定了实际进行的处理。
为什么要弄得这么复杂
Visitor是将处理从数据结构中分离开来。
开闭原则–对扩展开放,对修改关闭
开闭原则:在不修改现有代码的前提下进行扩展。
易于增加ConcreteVisitor角色
难以增加ConcreteElement角色
Visitor工作所需的条件
visitor只有从数据结构中获取了足够多的信息后才能工作(Directory的Iterator),不然无法工作。
缺点是,如果公开了不应当被公开的信息,将来对数据结构的改良就会变得非常困难。
Chain of Resposibility模式
推卸责任
我们考虑将多个对象组成一条职责链,然后按照他们呢在职责链上的顺序一个一个地找出到底应该谁来负责处理。
可以弱化为 “请求方” 和 “处理方”之间地关联关系,让双方各自都可以成为可独立复用地组件。
1、示例
代码清单
1)Trouble
public class Trouble {
private int number;
public Trouble(int number){
this.number = number;
}
public int getNumber(){
return number;
}
public String toString(){
return "[Touble" + number + "]";
}
}
2)Support
public abstract class Support {
private String name;
private Support next;
public Support(String name){
this.name = name;
}
public Support setNext(Support next){
this.next = next;
return next;
}
public final void support(Trouble trouble){
if(resolve(trouble)){
done(trouble);
}
else if(next != null){
next.support(trouble);
}
else fail(trouble);
}
public String toString(){
return "[" + name + "]";
}
protected abstract boolean resolve(Trouble touble);
protected void done(Trouble trouble){
System.out.println(trouble + " is resolved by " + this + ".");
}
protected void fail(Trouble trouble){
System.out.println(trouble + " cannot be resolved");
}
}
3)NoSupport
public class NoSupport extends Support{
public NoSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble touble) {
return false;
}
}
4)LimitSupport
public class LimitSupport extends Support{
private int limit;
public LimitSupport(String name, int limit) {
super(name);
this.limit = limit;
}
@Override
protected boolean resolve(Trouble touble) {
if(touble.getNumber() < limit){
return true;
}
return false;
}
}
5)SpecialSupport
public class SpecialSupport extends Support{
private int number;
public SpecialSupport(String name, int number) {
super(name);
this.number = number;
}
@Override
protected boolean resolve(Trouble touble) {
if(touble.getNumber() == number){
return true;
}
return false;
}
}
6)OddSupport
public class OddSupport extends Support{
public OddSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble touble) {
if(touble.getNumber() % 2 == 1){
return true;
}
return false;
}
}
7)Main
public class ChainMain {
public static void main(String[] args) {
Support alice = new NoSupport("Alice");
Support bob = new LimitSupport("Bob", 100);
Support charlie = new SpecialSupport("Charlie", 429);
Support diana = new LimitSupport("Diana", 200);
Support elmo = new OddSupport("Elmo");
Support fred = new LimitSupport("Fred", 300);
alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
for(int i = 0; i < 500; i+= 33){
alice.support(new Trouble(i));
}
}
}
时序图
2、角色
1)Handler(处理着) =》Support
定义了处理请求地接口(API).Handler角色知道“下一个处理者”是谁,如果自己无法处理请求,它会将请求转给下一个处理者。 当然 下一个处理者也是 Handler角色。
2)ConcreteHandler(具体的处理者) =》NoSupport、LimitSupport、OddSupport、SpecialSupport
是处理请求地具体角色。
3)Client(请求者)
向第一个ConcreteHandler角色发送请求地角色。
3、思路要点
弱化了发出请求地人和处理请求的人之间的关系
可以动态地改变职责链
专注于自己的工作
推卸请求会导致处理延迟吗
确实如此。