Java的23种设计模式,详细讲解(二)
本人免费整理了java高级资料,涵盖了java、redis、mongodb、mysql、zookeeper、spring cloud、dubbo高并发分布式等教程,一共30g,需要自己领取。
传送门:https://mp.weixin.qq.com/s/jzddfh-7ynudmkjt0irl8q
1. 责任链(chain of responsibility)
intent
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
class diagram
- handler:定义处理请求的接口,并且实现后继链(successor)
implementation
public abstract class handler { protected handler successor; public handler(handler successor) { this.successor = successor; } protected abstract void handlerequest(request request); } public class concretehandler1 extends handler { public concretehandler1(handler successor) { super(successor); } @override protected void handlerequest(request request) { if (request.gettype() == requesttype.type1) { system.out.println(request.getname() + " is handle by concretehandler1"); return; } if (successor != null) { successor.handlerequest(request); } } } public class concretehandler2 extends handler { public concretehandler2(handler successor) { super(successor); } @override protected void handlerequest(request request) { if (request.gettype() == requesttype.type2) { system.out.println(request.getname() + " is handle by concretehandler2"); return; } if (successor != null) { successor.handlerequest(request); } } } public class request { private requesttype type; private string name; public request(requesttype type, string name) { this.type = type; this.name = name; } public requesttype gettype() { return type; } public string getname() { return name; } } public enum requesttype { type1, type2 } public class client { public static void main(string[] args) { handler handler1 = new concretehandler1(null); handler handler2 = new concretehandler2(handler1); request request1 = new request(requesttype.type1, "request1"); handler2.handlerequest(request1); request request2 = new request(requesttype.type2, "request2"); handler2.handlerequest(request2); } } request1 is handle by concretehandler1 request2 is handle by concretehandler2
jdk
2. 命令(command)
intent
将命令封装成对象中,具有以下作用:
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
class diagram
- command:命令
- receiver:命令接收者,也就是命令真正的执行者
- invoker:通过它来调用命令
- client:可以设置命令与命令的接收者
implementation
设计一个遥控器,可以控制电灯开关。
public interface command { void execute(); } public class lightoncommand implements command { light light; public lightoncommand(light light) { this.light = light; } @override public void execute() { light.on(); } } public class lightoffcommand implements command { light light; public lightoffcommand(light light) { this.light = light; } @override public void execute() { light.off(); } } public class light { public void on() { system.out.println("light is on!"); } public void off() { system.out.println("light is off!"); } } /** * 遥控器 */ public class invoker { private command[] oncommands; private command[] offcommands; private final int slotnum = 7; public invoker() { this.oncommands = new command[slotnum]; this.offcommands = new command[slotnum]; } public void setoncommand(command command, int slot) { oncommands[slot] = command; } public void setoffcommand(command command, int slot) { offcommands[slot] = command; } public void onbuttonwaspushed(int slot) { oncommands[slot].execute(); } public void offbuttonwaspushed(int slot) { offcommands[slot].execute(); } } public class client { public static void main(string[] args) { invoker invoker = new invoker(); light light = new light(); command lightoncommand = new lightoncommand(light); command lightoffcommand = new lightoffcommand(light); invoker.setoncommand(lightoncommand, 0); invoker.setoffcommand(lightoffcommand, 0); invoker.onbuttonwaspushed(0); invoker.offbuttonwaspushed(0); } }
jdk
3. 解释器(interpreter)
intent
为语言创建解释器,通常由语言的语法和语法分析来定义。
class diagram
- terminalexpression:终结符表达式,每个终结符都需要一个 terminalexpression。
- context:上下文,包含解释器之外的一些全局信息。
implementation
以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。
例如一颗解析树为 d and (a or (b c)),文本 "d a" 满足该解析树定义的规则。
这里的 context 指的是 string。
public abstract class expression { public abstract boolean interpret(string str); } public class terminalexpression extends expression { private string literal = null; public terminalexpression(string str) { literal = str; } public boolean interpret(string str) { stringtokenizer st = new stringtokenizer(str); while (st.hasmoretokens()) { string test = st.nexttoken(); if (test.equals(literal)) { return true; } } return false; } } public class andexpression extends expression { private expression expression1 = null; private expression expression2 = null; public andexpression(expression expression1, expression expression2) { this.expression1 = expression1; this.expression2 = expression2; } public boolean interpret(string str) { return expression1.interpret(str) && expression2.interpret(str); } } public class orexpression extends expression { private expression expression1 = null; private expression expression2 = null; public orexpression(expression expression1, expression expression2) { this.expression1 = expression1; this.expression2 = expression2; } public boolean interpret(string str) { return expression1.interpret(str) || expression2.interpret(str); } } public class client { /** * 构建解析树 */ public static expression buildinterpretertree() { // literal expression terminal1 = new terminalexpression("a"); expression terminal2 = new terminalexpression("b"); expression terminal3 = new terminalexpression("c"); expression terminal4 = new terminalexpression("d"); // b c expression alternation1 = new orexpression(terminal2, terminal3); // a or (b c) expression alternation2 = new orexpression(terminal1, alternation1); // d and (a or (b c)) return new andexpression(terminal4, alternation2); } public static void main(string[] args) { expression define = buildinterpretertree(); string context1 = "d a"; string context2 = "a b"; system.out.println(define.interpret(context1)); system.out.println(define.interpret(context2)); } } true false
jdk
- java.util.pattern
- java.text.normalizer
- all subclasses of java.text.format
- javax.el.elresolver
4. 迭代器(iterator)
intent
提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
class diagram
- aggregate 是聚合类,其中 createiterator() 方法可以产生一个 iterator;
- iterator 主要定义了 hasnext() 和 next() 方法。
- client 组合了 aggregate,为了迭代遍历 aggregate,也需要组合 iterator。
implementation
public interface aggregate { iterator createiterator(); } public class concreteaggregate implements aggregate { private integer[] items; public concreteaggregate() { items = new integer[10]; for (int i = 0; i < items.length; i++) { items[i] = i; } } @override public iterator createiterator() { return new concreteiterator<integer>(items); } } public interface iterator<item> { item next(); boolean hasnext(); } public class concreteiterator<item> implements iterator { private item[] items; private int position = 0; public concreteiterator(item[] items) { this.items = items; } @override public object next() { return items[position++]; } @override public boolean hasnext() { return position < items.length; } } public class client { public static void main(string[] args) { aggregate aggregate = new concreteaggregate(); iterator<integer> iterator = aggregate.createiterator(); while (iterator.hasnext()) { system.out.println(iterator.next()); } } }
jdk
5. 中介者(mediator)
intent
集中相关对象之间复杂的沟通和控制方式。
class diagram
- mediator:中介者,定义一个接口用于与各同事(colleague)对象通信。
- colleague:同事,相关对象
implementation
alarm(闹钟)、coffeepot(咖啡壶)、calendar(日历)、sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:
使用中介者模式可以将复杂的依赖结构变成星形结构:
public abstract class colleague { public abstract void onevent(mediator mediator); } public class alarm extends colleague { @override public void onevent(mediator mediator) { mediator.doevent("alarm"); } public void doalarm() { system.out.println("doalarm()"); } } public class coffeepot extends colleague { @override public void onevent(mediator mediator) { mediator.doevent("coffeepot"); } public void docoffeepot() { system.out.println("docoffeepot()"); } } public class calender extends colleague { @override public void onevent(mediator mediator) { mediator.doevent("calender"); } public void docalender() { system.out.println("docalender()"); } } public class sprinkler extends colleague { @override public void onevent(mediator mediator) { mediator.doevent("sprinkler"); } public void dosprinkler() { system.out.println("dosprinkler()"); } } public abstract class mediator { public abstract void doevent(string eventtype); } public class concretemediator extends mediator { private alarm alarm; private coffeepot coffeepot; private calender calender; private sprinkler sprinkler; public concretemediator(alarm alarm, coffeepot coffeepot, calender calender, sprinkler sprinkler) { this.alarm = alarm; this.coffeepot = coffeepot; this.calender = calender; this.sprinkler = sprinkler; } @override public void doevent(string eventtype) { switch (eventtype) { case "alarm": doalarmevent(); break; case "coffeepot": docoffeepotevent(); break; case "calender": docalenderevent(); break; default: dosprinklerevent(); } } public void doalarmevent() { alarm.doalarm(); coffeepot.docoffeepot(); calender.docalender(); sprinkler.dosprinkler(); } public void docoffeepotevent() { // ... } public void docalenderevent() { // ... } public void dosprinklerevent() { // ... } } public class client { public static void main(string[] args) { alarm alarm = new alarm(); coffeepot coffeepot = new coffeepot(); calender calender = new calender(); sprinkler sprinkler = new sprinkler(); mediator mediator = new concretemediator(alarm, coffeepot, calender, sprinkler); // 闹钟事件到达,调用中介者就可以操作相关对象 alarm.onevent(mediator); } } doalarm() docoffeepot() docalender()
dosprinkler()
jdk
- all schedulexxx() methods of java.util.timer
- java.util.concurrent.executor#execute()
- submit() and invokexxx() methods of java.util.concurrent.executorservice
- schedulexxx() methods of java.util.concurrent.scheduledexecutorservice
- java.lang.reflect.method#invoke()
6. 备忘录(memento)
intent
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
class diagram
- originator:原始对象
- caretaker:负责保存好备忘录
- menento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 originator 访问本备忘录的内部状态。
implementation
以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。
实现参考:memento pattern - calculator example - java sourcecode
/** * originator interface */ public interface calculator { // create memento previouscalculationtocaretaker backuplastcalculation(); // setmemento void restorepreviouscalculation(previouscalculationtocaretaker memento); int getcalculationresult(); void setfirstnumber(int firstnumber); void setsecondnumber(int secondnumber); } /** * originator implementation */ public class calculatorimp implements calculator { private int firstnumber; private int secondnumber; @override public previouscalculationtocaretaker backuplastcalculation() { // create a memento object used for restoring two numbers return new previouscalculationimp(firstnumber, secondnumber); } @override public void restorepreviouscalculation(previouscalculationtocaretaker memento) { this.firstnumber = ((previouscalculationtooriginator) memento).getfirstnumber(); this.secondnumber = ((previouscalculationtooriginator) memento).getsecondnumber(); } @override public int getcalculationresult() { // result is adding two numbers return firstnumber + secondnumber; } @override public void setfirstnumber(int firstnumber) { this.firstnumber = firstnumber; } @override public void setsecondnumber(int secondnumber) { this.secondnumber = secondnumber; } } /** * memento interface to originator * * this interface allows the originator to restore its state */ public interface previouscalculationtooriginator { int getfirstnumber(); int getsecondnumber(); } /** * memento interface to calculatoroperator (caretaker) */ public interface previouscalculationtocaretaker { // no operations permitted for the caretaker } /** * memento object implementation * <p> * note that this object implements both interfaces to originator and caretaker */ public class previouscalculationimp implements previouscalculationtocaretaker, previouscalculationtooriginator { private int firstnumber; private int secondnumber; public previouscalculationimp(int firstnumber, int secondnumber) { this.firstnumber = firstnumber; this.secondnumber = secondnumber; } @override public int getfirstnumber() { return firstnumber; } @override public int getsecondnumber() { return secondnumber; } } /** * caretaker object */ public class client { public static void main(string[] args) { // program starts calculator calculator = new calculatorimp(); // assume user enters two numbers calculator.setfirstnumber(10); calculator.setsecondnumber(100); // find result system.out.println(calculator.getcalculationresult()); // store result of this calculation in case of error previouscalculationtocaretaker memento = calculator.backuplastcalculation(); // user enters a number calculator.setfirstnumber(17); // user enters a wrong second number and calculates result calculator.setsecondnumber(-290); // calculate result system.out.println(calculator.getcalculationresult()); // user hits ctrl + z to undo last operation and see last result calculator.restorepreviouscalculation(memento); // result restored system.out.println(calculator.getcalculationresult()); } } 110 -273 110
jdk
- java.io.serializable
7. 观察者(observer)
intent
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(subject)是被观察的对象,而其所有依赖者(observer)称为观察者。
class diagram
主题(subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。
观察者(observer)的注册功能需要调用主题的 registerobserver() 方法。
implementation
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。
public interface subject { void registerobserver(observer o); void removeobserver(observer o); void notifyobserver(); } public class weatherdata implements subject { private list<observer> observers; private float temperature; private float humidity; private float pressure; public weatherdata() { observers = new arraylist<>(); } public void setmeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; notifyobserver(); } @override public void registerobserver(observer o) { observers.add(o); } @override public void removeobserver(observer o) { int i = observers.indexof(o); if (i >= 0) { observers.remove(i); } } @override public void notifyobserver() { for (observer o : observers) { o.update(temperature, humidity, pressure); } } } public interface observer { void update(float temp, float humidity, float pressure); } public class statisticsdisplay implements observer { public statisticsdisplay(subject weatherdata) { weatherdata.reisterobserver(this); } @override public void update(float temp, float humidity, float pressure) { system.out.println("statisticsdisplay.update: " + temp + " " + humidity + " " + pressure); } } public class currentconditionsdisplay implements observer { public currentconditionsdisplay(subject weatherdata) { weatherdata.registerobserver(this); } @override public void update(float temp, float humidity, float pressure) { system.out.println("currentconditionsdisplay.update: " + temp + " " + humidity + " " + pressure); } } public class weatherstation { public static void main(string[] args) { weatherdata weatherdata = new weatherdata(); currentconditionsdisplay currentconditionsdisplay = new currentconditionsdisplay(weatherdata); statisticsdisplay statisticsdisplay = new statisticsdisplay(weatherdata); weatherdata.setmeasurements(0, 0, 0); weatherdata.setmeasurements(1, 1, 1); } } currentconditionsdisplay.update: 0.0 0.0 0.0 statisticsdisplay.update: 0.0 0.0 0.0 currentconditionsdisplay.update: 1.0 1.0 1.0 statisticsdisplay.update: 1.0 1.0 1.0
jdk
8. 状态(state)
intent
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
class diagram
implementation
糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。
public interface state { /** * 投入 25 分钱 */ void insertquarter(); /** * 退回 25 分钱 */ void ejectquarter(); /** * 转动曲柄 */ void turncrank(); /** * 发放糖果 */ void dispense(); } public class hasquarterstate implements state { private gumballmachine gumballmachine; public hasquarterstate(gumballmachine gumballmachine) { this.gumballmachine = gumballmachine; } @override public void insertquarter() { system.out.println("you can't insert another quarter"); } @override public void ejectquarter() { system.out.println("quarter returned"); gumballmachine.setstate(gumballmachine.getnoquarterstate()); } @override public void turncrank() { system.out.println("you turned..."); gumballmachine.setstate(gumballmachine.getsoldstate()); } @override public void dispense() { system.out.println("no gumball dispensed"); } } public class noquarterstate implements state { gumballmachine gumballmachine; public noquarterstate(gumballmachine gumballmachine) { this.gumballmachine = gumballmachine; } @override public void insertquarter() { system.out.println("you insert a quarter"); gumballmachine.setstate(gumballmachine.gethasquarterstate()); } @override public void ejectquarter() { system.out.println("you haven't insert a quarter"); } @override public void turncrank() { system.out.println("you turned, but there's no quarter"); } @override public void dispense() { system.out.println("you need to pay first"); } } public class soldoutstate implements state { gumballmachine gumballmachine; public soldoutstate(gumballmachine gumballmachine) { this.gumballmachine = gumballmachine; } @override public void insertquarter() { system.out.println("you can't insert a quarter, the machine is sold out"); } @override public void ejectquarter() { system.out.println("you can't eject, you haven't inserted a quarter yet"); } @override public void turncrank() { system.out.println("you turned, but there are no gumballs"); } @override public void dispense() { system.out.println("no gumball dispensed"); } } public class soldstate implements state { gumballmachine gumballmachine; public soldstate(gumballmachine gumballmachine) { this.gumballmachine = gumballmachine; } @override public void insertquarter() { system.out.println("please wait, we're already giving you a gumball"); } @override public void ejectquarter() { system.out.println("sorry, you already turned the crank"); } @override public void turncrank() { system.out.println("turning twice doesn't get you another gumball!"); } @override public void dispense() { gumballmachine.releaseball(); if (gumballmachine.getcount() > 0) { gumballmachine.setstate(gumballmachine.getnoquarterstate()); } else { system.out.println("oops, out of gumballs"); gumballmachine.setstate(gumballmachine.getsoldoutstate()); } } } public class gumballmachine { private state soldoutstate; private state noquarterstate; private state hasquarterstate; private state soldstate; private state state; private int count = 0; public gumballmachine(int numbergumballs) { count = numbergumballs; soldoutstate = new soldoutstate(this); noquarterstate = new noquarterstate(this); hasquarterstate = new hasquarterstate(this); soldstate = new soldstate(this); if (numbergumballs > 0) { state = noquarterstate; } else { state = soldoutstate; } } public void insertquarter() { state.insertquarter(); } public void ejectquarter() { state.ejectquarter(); } public void turncrank() { state.turncrank(); state.dispense(); } public void setstate(state state) { this.state = state; } public void releaseball() { system.out.println("a gumball comes rolling out the slot..."); if (count != 0) { count -= 1; } } public state getsoldoutstate() { return soldoutstate; } public state getnoquarterstate() { return noquarterstate; } public state gethasquarterstate() { return hasquarterstate; } public state getsoldstate() { return soldstate; } public int getcount() { return count; } } public class client { public static void main(string[] args) { gumballmachine gumballmachine = new gumballmachine(5); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.ejectquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.ejectquarter(); gumballmachine.insertquarter(); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); } } you insert a quarter you turned... a gumball comes rolling out the slot... you insert a quarter quarter returned you turned, but there's no quarter you need to pay first you insert a quarter you turned... a gumball comes rolling out the slot... you insert a quarter you turned... a gumball comes rolling out the slot... you haven't insert a quarter you insert a quarter you can't insert another quarter you turned... a gumball comes rolling out the slot... you insert a quarter you turned... a gumball comes rolling out the slot... oops, out of gumballs you can't insert a quarter, the machine is sold out you turned, but there are no gumballs no gumball dispensed
9. 策略(strategy)
intent
定义一系列算法,封装每个算法,并使它们可以互换。
策略模式可以让算法独立于使用它的客户端。
class diagram
- strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
- context 是使用到该算法族的类,其中的 dosomething() 方法会调用 behavior(),setstrategy(strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 context 所使用的算法。
与状态模式的比较
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 context 所组合的 state 对象,而策略模式是通过 context 本身的决策来改变组合的 strategy 对象。所谓的状态转移,是指 context 在运行过程中由于一些条件发生改变而使得 state 对象发生改变,注意必须要是在运行过程中。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 context 使用的算法。
implementation
设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。
public interface quackbehavior { void quack(); } public class quack implements quackbehavior { @override public void quack() { system.out.println("quack!"); } } public class squeak implements quackbehavior{ @override public void quack() { system.out.println("squeak!"); } } public class duck { private quackbehavior quackbehavior; public void performquack() { if (quackbehavior != null) { quackbehavior.quack(); } } public void setquackbehavior(quackbehavior quackbehavior) { this.quackbehavior = quackbehavior; } } public class client { public static void main(string[] args) { duck duck = new duck(); duck.setquackbehavior(new squeak()); duck.performquack(); duck.setquackbehavior(new quack()); duck.performquack(); } } squeak! quack!
jdk
- java.util.comparator#compare()
- javax.servlet.http.httpservlet
- javax.servlet.filter#dofilter()
10. 模板方法(template method)
intent
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
class diagram
implementation
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。
public abstract class caffeinebeverage { final void preparerecipe() { boilwater(); brew(); pourincup(); addcondiments(); } abstract void brew(); abstract void addcondiments(); void boilwater() { system.out.println("boilwater"); } void pourincup() { system.out.println("pourincup"); } } public class coffee extends caffeinebeverage { @override void brew() { system.out.println("coffee.brew"); } @override void addcondiments() { system.out.println("coffee.addcondiments"); } } public class tea extends caffeinebeverage { @override void brew() { system.out.println("tea.brew"); } @override void addcondiments() { system.out.println("tea.addcondiments"); } } public class client { public static void main(string[] args) { caffeinebeverage caffeinebeverage = new coffee(); caffeinebeverage.preparerecipe(); system.out.println("-----------"); caffeinebeverage = new tea(); caffeinebeverage.preparerecipe(); } } boilwater coffee.brew pourincup coffee.addcondiments ----------- boilwater tea.brew pourincup tea.addcondiments
jdk
- java.util.collections#sort()
- java.io.inputstream#skip()
- java.io.inputstream#read()
- java.util.abstractlist#indexof()
11. 访问者(visitor)
intent
为一个对象结构(比如组合结构)增加新能力。
class diagram
- visitor:访问者,为每一个 concreteelement 声明一个 visit 操作
- concretevisitor:具体访问者,存储遍历过程中的累计结果
- objectstructure:对象结构,可以是组合结构,或者是一个集合。
implementation
public interface element { void accept(visitor visitor); } class customergroup { private list<customer> customers = new arraylist<>(); void accept(visitor visitor) { for (customer customer : customers) { customer.accept(visitor); } } void addcustomer(customer customer) { customers.add(customer); } } public class customer implements element { private string name; private list<order> orders = new arraylist<>(); customer(string name) { this.name = name; } string getname() { return name; } void addorder(order order) { orders.add(order); } public void accept(visitor visitor) { visitor.visit(this); for (order order : orders) { order.accept(visitor); } } } public class order implements element { private string name; private list<item> items = new arraylist(); order(string name) { this.name = name; } order(string name, string itemname) { this.name = name; this.additem(new item(itemname)); } string getname() { return name; } void additem(item item) { items.add(item); } public void accept(visitor visitor) { visitor.visit(this); for (item item : items) { item.accept(visitor); } } } public class item implements element { private string name; item(string name) { this.name = name; } string getname() { return name; } public void accept(visitor visitor) { visitor.visit(this); } } public interface visitor { void visit(customer customer); void visit(order order); void visit(item item); } public class generalreport implements visitor { private int customersno; private int ordersno; private int itemsno; public void visit(customer customer) { system.out.println(customer.getname()); customersno++; } public void visit(order order) { system.out.println(order.getname()); ordersno++; } public void visit(item item) { system.out.println(item.getname()); itemsno++; } public void displayresults() { system.out.println("number of customers: " + customersno); system.out.println("number of orders: " + ordersno); system.out.println("number of items: " + itemsno); } } public class client { public static void main(string[] args) { customer customer1 = new customer("customer1"); customer1.addorder(new order("order1", "item1")); customer1.addorder(new order("order2", "item1")); customer1.addorder(new order("order3", "item1")); order order = new order("order_a"); order.additem(new item("item_a1")); order.additem(new item("item_a2")); order.additem(new item("item_a3")); customer customer2 = new customer("customer2"); customer2.addorder(order); customergroup customers = new customergroup(); customers.addcustomer(customer1); customers.addcustomer(customer2); generalreport visitor = new generalreport(); customers.accept(visitor); visitor.displayresults(); } } customer1 order1 item1 order2 item1 order3 item1 customer2 order_a item_a1 item_a2 item_a3 number of customers: 2 number of orders: 4 number of items: 6
jdk
- javax.lang.model.element.element and javax.lang.model.element.elementvisitor
- javax.lang.model.type.typemirror and javax.lang.model.type.typevisitor
12. 空对象(null)
intent
使用什么都不做的空对象来代替 null。
一个方法返回 null,意味着方法的调用端需要去检查返回值是否是 null,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
class diagram
implementation
public abstract class abstractoperation { abstract void request(); } public class realoperation extends abstractoperation { @override void request() { system.out.println("do something"); } } public class nulloperation extends abstractoperation{ @override void request() { // do nothing } } public class client { public static void main(string[] args) { abstractoperation abstractoperation = func(-1); abstractoperation.request(); } public static abstractoperation func(int para) { if (para < 0) { return new nulloperation(); } return new realoperation(); } }