最近参加了一次面试,其中笔试题有一道编程题,在更换掉试题的描述场景后,大意如下:
上课铃声响起,学生A/B/C/D进入教室;下课铃声响起,学生A/B/C/D离开教室。
要求使用设计模式的思想完成铃与学生两个类的解耦并画出UML类图。
看到这道题之后自己第一时间便想到了装饰器模式,定义一个装饰类继承铃的接口,在上课铃与下课铃的接口中添加学生们的动作,UML类图如下:
最后的确做到了解耦,但总觉得与装饰器模式的应用场景不太匹配,最后面试官给了个提示——观察者模式——于是豁然开朗,本题的场景毫无疑问更适合使用观察者模式来解决,观察者模式定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
该道题使用观察者模式的UML类图如下:
实现代码如下(Java:jdk1.8.0_144):
import java.util.Observable; public abstract class IBell extends Observable { public enum State { 上课, 下课 } public abstract void firstRing(); public abstract void secondRing(); }
public class Bell extends IBell { @Override public void firstRing() { System.out.println("上课铃响了!!!"); super.setChanged();// 修改对象状态才能触发观察者的通知事件 this.notifyObservers(State.上课); } @Override public void secondRing() { System.out.println("下课铃响了!!!"); super.setChanged();// 修改对象状态才能触发观察者的通知事件 this.notifyObservers(State.下课); } }
import java.util.Observable; import java.util.Observer; import org.lxp.dailylog.web.util.IBell.State; public abstract class IStudent implements Observer { public abstract void enterClassRoom(); public abstract void leaveClassRoom(); @Override public void update(Observable o, Object arg) { switch (State.valueOf(arg.toString())) { case 上课: enterClassRoom(); break; case 下课: leaveClassRoom(); break; } } }
public class Student extends IStudent { private String name; public Student(String name) { this.name = name; } @Override public void enterClassRoom() { System.out.println("Student " + this.name + " enters classroom"); } @Override public void leaveClassRoom() { System.out.println("Student " + this.name + " leaves classroom"); } }
public class Test { public static void main(String[] args) { Student A = new Student("A"); Student B = new Student("B"); Student C = new Student("C"); Student D = new Student("D"); Bell bell = new Bell(); bell.addObserver(D); bell.addObserver(C); bell.addObserver(B); bell.addObserver(A); bell.firstRing(); bell.secondRing(); } }
输出结果如下: