时间: 2021-07-31 作者:daque
一、媒介 对于体例中一个仍旧实行的类档次构造,咱们仍旧给它供给了满意需要的接口。然而面临新减少的需要,咱们该当如何做呢?即使这是为数不多的几次变化,并且你不必为了一个需要的安排而将所有类档次构造十足地窜改一遍,那么径直在原有类档次构造上窜改大概是个 不错 的办法。 然而常常咱们遇到的却是:如许的需要变化大概会不停的爆发;更要害的是需要的任何变化大概都要让你将所有类档次构造窜改个底朝天……。这种一致的操纵散布在各别的类内里,不是一个好局面,咱们要对这个构造重构一下了。 那么,考察者形式大概是你很好的采用。 二、设置与构造 考察者形式,望文生义运用了这个形式后就不妨在不窜改已有步调构造的基础下,经过增添特殊的“考察者”来实行对已有代码功效的提高。 《安排形式》一书对于考察者形式给出的设置为:表白一个效率于某东西构造中的各元素的操纵。它使你不妨在不变换各元素的类的基础下设置效率于那些元素的新操纵。从设置不妨看出构造东西是运用考察者形式必需前提,并且这个构造东西必需生存遍历自己各个东西的本领。这便一致于java中的collection观念了。 以次是考察者形式的构成构造: 1) 考察者脚色(visitor):为该东西构造中简直元素脚色证明一个考察操纵接口。该操纵接口的名字和参数标识了发送考察乞求给简直考察者的简直元素脚色。如许考察者就不妨经过该元素脚色的一定接口径直考察它。 2) 简直考察者脚色(concrete visitor):实行每个由考察者脚色(visitor)证明的操纵。 3) 元素脚色(element):设置一个accept操纵,它以一个考察者为参数。 4) 简直元素脚色(concrete element):实行由元素脚色供给的accept操纵。 5) 东西构造脚色(object structure):这是运用考察者形式必备的脚色。它要完备以次特性:能列举它的元素;不妨供给一个高层的接口以承诺该考察者考察它的元素;不妨是一个复合(拉拢形式)或是一个汇合,如一个列表或一个无序汇合。 来张类图就能越发明显的看清考察者形式的构造了。
那么像弁言中设想的。咱们该当做些什么本领让考察者形式跑起来呢?开始咱们要在原有的类档次构造中增添accept本领。而后将这个类档次中的类放到一个东西构造中去。如许再去创造考察者脚色…… 三、举例 自己体验简直不幸,没能找到考察者形式在本质运用中的例子。只好借《thinking in patterns with java》中的熏陶代码一用。我略微做了下窜改。 import java.util.*; import junit.framework.*; //考察者脚色 interface visitor { void visit(gladiolus g); void visit(runuculus r); void visit(chrysanthemum c); } // the flower hierarchy cannot be changed: //元素脚色 interface flower { void accept(visitor v); } //以次三个简直元素脚色 class gladiolus implements flower { public void accept(visitor v) { v.visit(this);} } class runuculus implements flower { public void accept(visitor v) { v.visit(this);} } class chrysanthemum implements flower { public void accept(visitor v) { v.visit(this);} } // add the ability to produce a string: //实行的简直考察者脚色 class stringval implements visitor { string s; public string tostring() { return s; } public void visit(gladiolus g) { s = "gladiolus"; } public void visit(runuculus r) { s = "runuculus"; } public void visit(chrysanthemum c) { s = "chrysanthemum"; } } // add the ability to do "bee" activities: //另一个简直考察者脚色 class bee implements visitor { public void visit(gladiolus g) { system.out.println("bee and gladiolus"); } public void visit(runuculus r) { system.out.println("bee and runuculus"); } public void visit(chrysanthemum c) { system.out.println("bee and chrysanthemum"); } } //这是一个东西天生器 //这不是一个完备的东西构造,这边只是是模仿东西构造中的元素 class flowergenerator { private static random rand = new random(); public static flower newflower() { switch (rand.nextint(3)) { default: case 0: return new gladiolus(); case 1: return new runuculus(); case 2: return new chrysanthemum(); } } } //存户 尝试步调 public class beeandflowers extends testcase { /* 在这边你能看到考察者形式实行的过程: 开始在存户端先赢得一个简直的考察者脚色 遍历东西构造 对每一个元素挪用accept本领,将简直考察者脚色传入 如许就实行了所有进程 */ //东西构造脚色在这边才 组建 上 list flowers = new arraylist(); public beeandflowers() { for(int i = 0; i < 10; i++) flowers.add(flowergenerator.newflower()); } visitor sval ; public void test() { // it’s almost as if i had a function to // produce a flower string representation: //这个场合你不妨窜改再不运用其余一个简直考察者脚色 sval = new stringval(); iterator it = flowers.iterator(); while(it.hasnext()) { ((flower)it.next()).accept(sval); system.out.println(sval); } } public static void main(string args[]) { junit.textui.testrunner.run(beeandflowers.class); } } 四、双重分配 对了,你在上头的例子中领会到双重分配的实行了没有? 开始在存户步调中将简直考察者形式动作参数传播给简直元素脚色(加亮的场合所示)。这便实行了一次分配。 加入简直元素脚色后,简直元素角 色彩 用动作参数的简直考察者形式中的visitor本领,同声将本人(this)动作参数传播进去。简直考察者形式再按照参数的各别来采用本领来实行(加亮的场合所示)。这便实行了第二次分配。 五、优缺陷及实用情景 先来看下考察者形式的运用是否制止弁言中的苦楚。运用了考察者形式此后,对于从来的类档次减少新的操纵,只是须要实行一个简直考察者脚色就不妨了,而不用窜改所有类档次。并且如许适合“开闭规则”的诉求。并且每个简直的考察者脚色都对应于一个关系操纵,所以即使一个操纵的需要有变,那么只是窜改一个简直考察者脚色,而不必变换所有类档次。 可见考察者形式真实不妨处置咱们面对的少许题目。 并且因为考察者形式为咱们的体例多供给了一层“考察者”,所以咱们不妨在考察者中增添少许对元素脚色的特殊操纵。 然而“开闭规则”的按照老是部分的。即使体例中的类档次爆发了变革,会对考察者形式爆发怎么办的感化呢?你必需窜改考察者脚色和每一个简直考察者脚色…… 可见考察者脚色不符合简直元素脚色常常爆发变革的情景。并且考察者脚色要实行与元素脚色关系的操纵,就必需让元素脚色将本人里面属性表露出来,而在java中就表示着其它的东西也不妨考察。这就妨害了元素脚色的封装性。并且在考察者形式中,元素与考察者之间不妨传播的消息有限,这常常也会控制考察者形式的运用。 《安排形式》一书中给出了考察者形式实用的情景: 1) 一个东西构造包括很多类东西,它们有各别的接口,而你想对那些东西实行少许依附于其简直类的操纵。 2) 须要对一个东西构造中的东西举行很多各别的而且不关系的操纵,而你想制止让那些操纵“传染”那些东西的类。visitor使得你不妨将关系的操纵会合起来设置在一个类中。 3) 当该东西构造被很多运用共享时,用visitor形式让每个运用仅包括须要用到的操纵。 4) 设置东西构造的类很少变换,但常常须要在此构造上设置新的操纵。变换东西构造类须要重设置对一切考察者的接口,这大概须要很大的价格。即使东西构造类常常变换,那么大概仍旧在那些类中设置那些操纵较好。 你能否能很好的领会呢? 六、归纳 这是一个精巧并且搀杂的形式,它的运用前提比拟刻薄。当体例中生存着恒定的数据构造(比方上头的类档次),而有着各别的动作,那么考察者形式大概是个不错的采用。