Java设计模式之十一大行为模式上篇
观察者模式(Observer Pattern)
参考链接
https://mp.weixin.qq.com/s/1DqPjUZNT5UuRrZwl5QjqQ
概念
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
实现原理
对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化
比如气象局给各大网站发布天气信息,这里气象局是1的一方,各大网站是n的一方
实现方式
-
UML类图
-
案例源码
-
天气发布者
/** * @ClassName Weather * @Description TODO 天气实体类$ * @Author charlesYan * @Date 2020/3/13 12:01 * @Version 1.0 **/ public class Weather { private BigDecimal temperature; private BigDecimal pressure; private BigDecimal humidity; public Weather(BigDecimal temperature, BigDecimal pressure, BigDecimal humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; } public BigDecimal getTemperature() { return temperature; } public void setTemperature(BigDecimal temperature) { this.temperature = temperature; } public BigDecimal getPressure() { return pressure; } public void setPressure(BigDecimal pressure) { this.pressure = pressure; } public BigDecimal getHumidity() { return humidity; } public void setHumidity(BigDecimal humidity) { this.humidity = humidity; } @Override public String toString() { return "Weather{" + "temperature=" + temperature + ", pressure=" + pressure + ", humidity=" + humidity + '}'; } } /** * @ClassName Subject * @Description 天气发布者 * @Author charlesYan * @Date 2020/3/13 12:04 * @Version 1.0 **/ public interface Subject { public void registerObserver(Observer observer); public void notifyObservers(); public void removeObserver(Observer observer); } /** * @ClassName WeatherData * @Description TODO 天气信息$ * @Author charlesYan * @Date 2020/3/13 12:31 * @Version 1.0 **/ public class WeatherData implements Subject { private Weather weather; private LinkedList<Observer> observers; public WeatherData() { observers = new LinkedList<Observer>(); } public Weather getWeather() { return weather; } //更新天气信息 public void setWeather(Weather weather) { this.weather = weather; dataChange();//天气信息已更新 } //天气更新后通知全部观察者 public void dataChange(){ notifyObservers(); } //注册一个观察者 @Override public void registerObserver(Observer observer) { if (observer == null) throw new NullPointerException(); if (!observers.contains(observer)) { observers.add(observer); } } //通知所有观察者 @Override public void notifyObservers() { observers.forEach(observer -> { observer.update(weather); }); } @Override public void removeObserver(Observer observer) { if (observers.contains(observer)) { observers.remove(observer); } } }
-
观察者
/** * @ClassName Observer * @Description 观察者接口 * @Author charlesYan * @Date 2020/3/13 11:55 * @Version 1.0 **/ public interface Observer { public void update(Weather weather); } /** * @ClassName MojiWeather * @Description TODO 墨迹天气-观察者$ * @Author charlesYan * @Date 2020/3/13 14:21 * @Version 1.0 **/ public class MojiWeather implements Observer { private Weather weather; @Override public void update(Weather weather) { this.weather = weather; displayWeather(); } private void displayWeather() { System.out.println("墨迹天气实时播报:" + weather.toString()); } }
-
测试类
/** * @ClassName Client * @Description TODO 测试客户端$ * @Author charlesYan * @Date 2020/3/13 14:24 * @Version 1.0 **/ public class Client { public static void main(String[] args) { //创建天气信息 BigDecimal temperature = new BigDecimal("35"); BigDecimal pressure = new BigDecimal("32.89"); BigDecimal humidity = new BigDecimal("56.9767"); Weather weather = new Weather(temperature, pressure, humidity); //创建观察者 Observer mojiWeather = new MojiWeather(); //将观察者注册到weatherData WeatherData weatherData = new WeatherData(); weatherData.registerObserver(mojiWeather); //通知所有观察者 weatherData.setWeather(weather); } }
-
JDK源码应用
-
JDK中Observable类
//被观察者 public class Observable { private boolean changed = false; private Vector<Observer> obs; /** Construct an Observable with zero Observers. */ public Observable() { obs = new Vector<>(); } /** * Adds an observer to the set of observers for this object, provided * that it is not the same as some observer already in the set. * The order in which notifications will be delivered to multiple * observers is not specified. See the class comment. * * @param o an observer to be added. * @throws NullPointerException if the parameter o is null. */ public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } /** * Deletes an observer from the set of observers of this object. * Passing <CODE>null</CODE> to this method will have no effect. * @param o the observer to be deleted. */ public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } /** * If this object has changed, as indicated by the * <code>hasChanged</code> method, then notify all of its observers * and then call the <code>clearChanged</code> method to * indicate that this object has no longer changed. * <p> * Each observer has its <code>update</code> method called with two * arguments: this observable object and <code>null</code>. In other * words, this method is equivalent to: * <blockquote><tt> * notifyObservers(null)</tt></blockquote> * * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ Object[] arrLocal; synchronized (this) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } } //观察者 public interface Observer { /** * This method is called whenever the observed object is changed. An * application calls an <tt>Observable</tt> object's * <code>notifyObservers</code> method to have all the object's * observers notified of the change. * * @param o the observable object. * @param arg an argument passed to the <code>notifyObservers</code> * method. */ void update(Observable o, Object arg); }
-
源码分析
注意事项
-
可以以集合的方式来管理用户(Observer),包括注册,移除和通知
-
增加观察者时,不需要修改核心类WeatherData,遵守ocp原则
-
它定义了触发机制,适用场景有消息队列消费,Android 开发中的事件触发机制等等
模板方法模式(Template Method Pattern)
参考链接
https://mp.weixin.qq.com/s/3R81iasIH8d17pzWzHMuAg
概念
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
实现原理
-
介绍
在一个抽象类公开定义了执行它的方法的模板,它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 -
原理类图
实现方式
- UML类图
钩子方法实现
-
概念
在模板方法模式的父类中,定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为"钩子"
-
案例源码
/** * @ClassName SoyaMilk * @Description TODO 豆浆抽象类$ * @Author charlesYan * @Date 2020/3/9 11:06 * @Version 1.0 **/ public abstract class SoyaMilk { protected final void make(){ select(); if (isAddCondiments()) { addCondiments(); } soak(); beat(); } protected void select(){ System.out.println("第一步:选择上好黄豆"); } protected abstract void addCondiments(); protected void soak(){ System.out.println("第三步:将黄豆和配料开始浸泡"); } protected void beat(){ System.out.println("第四步:研磨黄豆和配料"); } //钩子方法 protected boolean isAddCondiments(){ return true; } } public class PureSoyaMilk extends SoyaMilk { @Override protected void addCondiments() { throw new RuntimeException("原味豆浆不能加入配料"); } //重写钩子方法 @Override protected boolean isAddCondiments() { return false; } } public class RedBeanSoyaMilk extends SoyaMilk { @Override protected void addCondiments() { System.out.println("第二步:加入精选红豆"); } } public class PeanutSoyaMilk extends SoyaMilk { @Override protected void addCondiments() { System.out.println("第二步:加入精选饱满花生"); } } /** * @ClassName Client * @Description TODO 测试类$ * @Author charlesYan * @Date 2020/3/9 11:07 * @Version 1.0 **/ public class Client { public static void main(String[] args) { System.out.println("-------------------------"); SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk(); peanutSoyaMilk.make(); System.out.println("-------------------------"); SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk(); redBeanSoyaMilk.make(); System.out.println("-------------------------"); SoyaMilk pureSoyaMilk = new PureSoyaMilk(); pureSoyaMilk.make(); } }
JDK源码应用
-
源码类图
-
Spring IOC容器初始化运行
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable { //声明了一个模板方法 void refresh() throws BeansException, IllegalStateException; } /**AbstractApplicationContext**/ public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { //模板方法的实现 public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); //obtainFreshBeanFactory方法调用了两个抽象方法refreshBeanFactory,getBeanFactory //这样具体要取那种BeanFactory容器的决定权交给了子类 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory);//钩子方法,让子类实现进行控制 this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh();//钩子方法 this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } } protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { this.refreshBeanFactory();//抽象的 return this.getBeanFactory(); } } /** GenericApplicationContext **/ public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { protected final void refreshBeanFactory() throws IllegalStateException { if (!this.refreshed.compareAndSet(false, true)) {//子类实现了refreshBeanFactory //实现交给子类 throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } else { this.beanFactory.setSerializationId(this.getId()); } } } /**GenericApplicationContext**/ public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { //同样实现了refreshBeanFactory和getBeanFactory //它的子类,就可以按它的实现方式来getBeanFactory,比如ClassPathXmmlApplicationConxtext }
注意事项
-
基本思想是:算法只存在于一个地方,也就是父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
-
**实现最大化代码复用。**父类的模板方法和已实现的某些步骤会被子类继承而直接使用
-
既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤实现
-
一般模板方法都加上final关键字,防止子类重写模板方法
-
不足之处是:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
-
使用场景:当要完成在某个过程,该过程要执行一系列步骤,这个一系列的步骤基本相同,但其个别步骤在实现时可能不同。
命令模式(Command Pattern)
参考链接
https://mp.weixin.qq.com/s/MtZLDcVGAmEKq0PmbcnYvQ
概念
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能
实现原理
-
原理类图
-
介绍
当我们需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需要在程序运行时指定具体的请求接收者即可,这时可以使用命令模式
实现方式
-
UML类图
-
案例源码
-
命令接口及实现类
/** * @ClassName Command * @Description 命令接口 * @Author charlesYan * @Date 2020/3/10 12:19 * @Version 1.0 **/ public interface Command { //执行命令 public void execute(); //撤销命令 public void undo(); } /** * @ClassName LightOffCommand * @Description TODO 电灯关闭命令$ * @Author charlesYan * @Date 2020/3/10 12:22 * @Version 1.0 **/ public class LightOffCommand implements Command { private LightReceiver lightReceiver; public LightOffCommand(LightReceiver lightReceiver) { this.lightReceiver = lightReceiver; } @Override public void execute() { lightReceiver.off(); } @Override public void undo() { lightReceiver.on(); } } /** * @ClassName LightOnCommand * @Description TODO 电灯打开命令$ * @Author charlesYan * @Date 2020/3/10 12:21 * @Version 1.0 **/ public class LightOnCommand implements Command { private LightReceiver lightReceiver; public LightOnCommand(LightReceiver lightReceiver) { this.lightReceiver = lightReceiver; } @Override public void execute() { lightReceiver.on(); } @Override public void undo() { lightReceiver.off(); } } /** * @ClassName NoCommand * @Description TODO 电灯空命令$ * 没有任何命令,即空执行: 用于初始化每个按钮, 当调用空命令时,对象什么都不做 * 其实,这样是一种设计模式, 可以省掉对空判断 * @Author charlesYan * @Date 2020/3/10 12:22 * @Version 1.0 **/ public class NoCommand implements Command { @Override public void execute() { } @Override public void undo() { } }
-
电灯实体类
/** * @ClassName LightReceiver * @Description TODO 电灯实体类$ * @Author charlesYan * @Date 2020/3/10 13:57 * @Version 1.0 **/ public class LightReceiver { public void on(){ System.out.println("打开电灯"); } public void off(){ System.out.println("关闭电灯"); } }
-
遥控器
/** * @ClassName RemoteController * @Description TODO 遥控器$ * @Author charlesYan * @Date 2020/3/10 14:11 * @Version 1.0 **/ public class RemoteController { //按键命令组 Command[] onCommands; Command[] offCommands; //执行撤销命令 Command undoCommand; //构造器-完成对按钮初始化 public RemoteController() { onCommands = new Command[5]; offCommands = new Command[5]; for (int i = 0; i < 5; i++) { onCommands[i] = new NoCommand(); offCommands[i] = new NoCommand(); } } //给我们的按钮设置你需要的命令 public void setCommand(int num, Command onCommand, Command offCommand) { onCommands[num] = onCommand; offCommands[num] = offCommand; } //按下开按钮 public void turnOn(int num){ //找到按下的开的按钮,并调用对应方法 onCommands[num].execute(); //记录这次操作,用于撤销 undoCommand = onCommands[num]; } //按下关按钮 public void turnOff(int num){ //找到按下的关按钮,并调用对应方法 offCommands[num].execute(); //记录这次操作,用于撤销 undoCommand = offCommands[num]; } //按下撤销按钮 public void undoCommand(){ undoCommand.undo(); } }
-
测试客户端
/** * @ClassName Client * @Description 命令模式测试类 * @Author charlesYan * @Date 2020/3/10 14:07 * @Version 1.0 **/ public class Client { public static void main(String[] args) { LightReceiver light = new LightReceiver(); //创建电灯相关开关命令 LightOnCommand lightOn = new LightOnCommand(light); LightOffCommand lightOff = new LightOffCommand(light); //需要一个遥控器 RemoteController remoteController = new RemoteController(); //给遥控器设置命令,比如num = 0 是电灯的开关操作 remoteController.setCommand(0,lightOn,lightOff); System.out.println("---------------按下灯的开按钮----------------"); remoteController.turnOn(0); System.out.println("---------------按下灯的关按钮----------------"); remoteController.turnOff(0); System.out.println("---------------按下灯的撤销按钮----------------"); remoteController.undoCommand(); } }
-
JDK源码应用
-
源码分析
-
JdbcTemplate源码应用
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { //充当士兵角色 @Nullable public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException { Assert.notNull(sql, "SQL must not be null"); Assert.notNull(rse, "ResultSetExtractor must not be null"); if (this.logger.isDebugEnabled()) { this.logger.debug("Executing SQL query [" + sql + "]"); } //具体实现命令接口,同时充当士兵的角色 class QueryStatementCallback implements StatementCallback<T>, SqlProvider { QueryStatementCallback() { } @Nullable public T doInStatement(Statement stmt) throws SQLException { ResultSet rs = null; Object var3; try { rs = stmt.executeQuery(sql); var3 = rse.extractData(rs); } finally { JdbcUtils.closeResultSet(rs); } return var3; } public String getSql() { return sql; } } return this.execute((StatementCallback)(new QueryStatementCallback())); } @Nullable public <T> T execute(StatementCallback<T> action) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); Connection con = DataSourceUtils.getConnection(this.obtainDataSource()); Statement stmt = null; Object var11; try { stmt = con.createStatement(); this.applyStatementSettings(stmt); T result = action.doInStatement(stmt); this.handleWarnings(stmt); var11 = result; } catch (SQLException var9) { String sql = getSql(action); JdbcUtils.closeStatement(stmt); stmt = null; DataSourceUtils.releaseConnection(con, this.getDataSource()); con = null; throw this.translateException("StatementCallback", sql, var9); } finally { JdbcUtils.closeStatement(stmt); DataSourceUtils.releaseConnection(con, this.getDataSource()); } return var11; } } //类似于命令接口 public interface StatementCallback<T> { @Nullable T doInStatement(Statement var1) throws SQLException, DataAccessException; }
注意事项
-
将发起请求的对象与执行请求的对象解耦。"请求发起者"和"请求执行者"之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用
-
可以设计一个命令队列,只要把命令对象放到队列,就可以多线程地执行命令
-
容易实现对请求撤销和重做
-
空命令也是一种设计模式,它为我们省去判空的操作,使我们不需要每按下一个按键都要判空。
-
不足之处:可能导致系统有过多的具体命令类,增加了系统的复杂度。
-
常用场景:界面的一个按钮都是一条命令、模拟CMD(DOS命令)、订单的撤销/恢复、触发-反馈机制
访问者模式(Visitor Pattern)
参考链接
https://mp.weixin.qq.com/s/PA0bdeeFYY3UEwNYfqH6IA
概念
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
实现原理
-
原理类图
-
介绍
在被访问的类里面加一个对外提供接待访问者的接口,主要将数据结构与数据操作分离,解决数据结构和操作耦合性问题
实现方式
-
UML类图
-
案例源码
将评委分为男人和女人,对歌手进行评价,使用访问者模式进行实现
-
评委相关类
/** * @ClassName Person * @Description TODO 评委抽象类$ * @Author charlesYan * @Date 2020/3/11 12:25 * @Version 1.0 **/ public abstract class Person { protected String name; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } //提供访问者访问接口 public abstract void accept(Action action); } /** * @ClassName Man * @Description TODO 男评委$ * @Author charlesYan * @Date 2020/3/11 12:32 * @Version 1.0 **/ public class Man extends Person { public Man(String name) { super(name); } @Override public void accept(Action action) { action.getManResult(this); } } /** * @ClassName Woman * @Description TODO 女评委$ * * 1. 这里我们使用到了双分派, 即首先在客户端程序中,将具体状态作为参数传递Woman中(第一次分派) * 2. 然后Woman 类调用作为参数的 "具体方法" 中方法getWomanResult, 同时将自己(this)作为参数传入,完成第二次的分派 * * @Author charlesYan * @Date 2020/3/11 12:38 * @Version 1.0 **/ public class Woman extends Person { public Woman(String name) { super(name); } @Override public void accept(Action action) { action.getWomanResult(this); } }
-
评价相关类
/** * @ClassName Action * @Description TODO 评判抽象类$ * @Author charlesYan * @Date 2020/3/11 12:30 * @Version 1.0 **/ public abstract class Action { public abstract void getManResult(Man man); public abstract void getWomanResult(Woman man); } /** * @ClassName Success * @Description TODO 通过$ * @Author charlesYan * @Date 2020/3/11 12:33 * @Version 1.0 **/ public class Success extends Action { @Override public void getManResult(Man man) { System.out.println(man.getName() + " 给该歌手 通过"); } @Override public void getWomanResult(Woman woman) { System.out.println(woman.getName() + " 给该歌手 通过"); } } /** * @ClassName Fail * @Description TODO 不通过$ * @Author charlesYan * @Date 2020/3/11 14:08 * @Version 1.0 **/ public class Fail extends Action { @Override public void getManResult(Man man) { System.out.println(man.getName() + " 给该歌手 不通过"); } @Override public void getWomanResult(Woman woman) { System.out.println(woman.getName() + " 给该歌手 不通过"); } }
-
数据结构类
/** * @ClassName ObjectStructure * @Description TODO 数据结构类$ * @Author charlesYan * @Date 2020/3/11 14:13 * @Version 1.0 **/ public class ObjectStructure { //维护一个集合 private List<Person> people = new LinkedList<>(); //增加到list public void attach(Person person){ people.add(person); } //从list中移除 public void detach(Person person){ people.remove(person); } //显示测评情况 public void display(Action action){ people.forEach(person -> { person.accept(action); }); } }
-
客户端测试类
/** * @ClassName Client * @Description TODO 客户端测试类$ * @Author charlesYan * @Date 2020/3/11 14:27 * @Version 1.0 **/ public class Client { public static void main(String[] args) { //创建执行成功评价的ObjectStructure ObjectStructure successStructure = new ObjectStructure(); successStructure.attach(new Man("ChalesYan")); successStructure.attach(new Woman("Frank")); //创建执行失败评价的ObjectStructure ObjectStructure failStructure = new ObjectStructure(); failStructure.attach(new Woman("Ellin")); Success success = new Success(); Fail fail = new Fail(); successStructure.display(success); failStructure.display(fail); } }
-
-
小结
-
所谓双分派是指不管类怎么变化,我们都能找到期望的方法运行。双分派意味着得到执行的操作取决于请求的种类和两个接收者类型
-
上述案例,假设需要添加一个Wait的状态类,考察Man类和Woman类的评判结果,由于使用了双分派,只需要增加一个Action子类即可在客户端调用即可,不需要改动其他代码
-
JDK源码应用
注意事项
-
应用场景:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式
-
优点:符合单一职责原则、让程序具有优秀的扩展性、灵活性较高;可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
-
缺点:具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,**违背了迪米特法则,**造成了具体元素变更比较困难。**违背了依赖倒转原则,**访问者依赖的是具体元素,而不是抽象元素
-
如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适
迭代器模式(Iterator Pattern)
参考链接
https://mp.weixin.qq.com/s/ItQUqfzzXw4387PVK0ib_g
概念
它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节
实现原理
- 原理类图
实现方式
-
UML类图
-
案例源码
-
学院相关类
/** * @ClassName College * @Description 大学接口 * @Author charlesYan * @Date 2020/3/12 12:11 * @Version 1.0 **/ public interface College { public String getName(); //增加系 public void addDepartment(String name,Integer amount); //创建不同类型迭代器用于遍历 public Iterator createIterator(); } /** * @ClassName ComputerCollege * @Description TODO 计算机学院$ * @Author charlesYan * @Date 2020/3/12 14:22 * @Version 1.0 **/ public class ComputerCollege implements College { private String name; private Department[] departments; private Integer length; public ComputerCollege(String name) { departments = new Department[10]; this.name = name; this.length = 0; } @Override public String getName() { return this.name; } @Override public void addDepartment(String name, Integer amount) { Department department = new Department(name, amount); departments[length] = department; length++; } @Override public Iterator createIterator() { return new ComputerCollegeIterator(departments); } } /** * @ClassName InfoCollege * @Description TODO 信息工程学院$ * @Author charlesYan * @Date 2020/3/12 15:21 * @Version 1.0 **/ public class InfoCollege implements College { private String name; private List<Department> departmentList; public InfoCollege(String name) { this.name = name; departmentList = new ArrayList<>(); } @Override public String getName() { return this.name; } @Override public void addDepartment(String name, Integer amount) { Department department = new Department(name, amount); departmentList.add(department); } @Override public Iterator createIterator() { return new InfoCollegeIterator(departmentList); } } /** * @ClassName Department * @Description TODO 系$ * @Author charlesYan * @Date 2020/3/12 14:26 * @Version 1.0 **/ public class Department { private String name; private Integer amount; public Department(String name, Integer amount) { this.name = name; this.amount = amount; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAmount() { return amount; } public void setAmount(Integer amount) { this.amount = amount; } }
-
迭代器相关类
/** * @ClassName ComputerCollegeIterator * @Description TODO 计算机学院迭代器$ * @Author charlesYan * @Date 2020/3/12 14:35 * @Version 1.0 **/ public class ComputerCollegeIterator implements Iterator { //存放系的方式-数组 private Department[] departments; //遍历位置 private Integer position; public ComputerCollegeIterator(Department[] departments) { this.departments = departments; this.position = 0; } //判断是否有下一个元素 @Override public boolean hasNext() { if (position >= departments.length || departments[position] == null) { return false; } return true; } //返回当前对象 @Override public Object next() { Department department = departments[position]; position++; return department; } } /** * @ClassName InfoCollegeIterator * @Description TODO 信息工程学院迭代器$ * @Author charlesYan * @Date 2020/3/12 15:31 * @Version 1.0 **/ public class InfoCollegeIterator implements Iterator { //存放系的方式-List private List<Department> departmentList; private Integer position; public InfoCollegeIterator(List<Department> departmentList) { this.departmentList = departmentList; position = 0; } @Override public boolean hasNext() { if (position < departmentList.size()) { return true; } return false; } @Override public Object next() { Department department = departmentList.get(position); position++; return department; } }
-
学院输出类
/** * @ClassName OutPutImpl * @Description TODO 学院输出类$ * @Author charlesYan * @Date 2020/3/12 14:46 * @Version 1.0 **/ public class OutPutImpl { //学院集合 private List<College> collegeList; public OutPutImpl(List<College> collegeList) { this.collegeList = collegeList; } //遍历所有学院,然后调用printDepartment输出各个学院的系 public void printCollege(){ //Java中的List已经实现Iterator Iterator<College> iterator = collegeList.iterator(); while (iterator.hasNext()) { //取出一个学院 College college = iterator.next(); System.out.println("===" +college.getName()+ "==="); //打印所有系 printDepartment(college.createIterator()); } } public void printDepartment(Iterator iterator){ while (iterator.hasNext()) { Department department = (Department) iterator.next(); System.out.println(department.getName() + "---" + department.getAmount() + "人"); } } }
-
测试类
public class Client { public static void main(String[] args) { //创建学院列表 List<College> collegeList = new ArrayList<>(); //创建计算机学院 ComputerCollege computerCollege = new ComputerCollege("计算机学院"); computerCollege.addDepartment("Java系",30); computerCollege.addDepartment("PHP系",50); computerCollege.addDepartment("Python系",70); computerCollege.addDepartment("C++系",80); computerCollege.addDepartment("人工智能系",10); //创建信息工程学院 InfoCollege infoCollege = new InfoCollege("信息工程学院"); infoCollege.addDepartment("电商系",20); infoCollege.addDepartment("运营系",10); infoCollege.addDepartment("管理系",30); collegeList.add(computerCollege); collegeList.add(infoCollege); OutPutImpl outPut = new OutPutImpl(collegeList); outPut.printCollege(); } }
-
JDK源码应用
-
源码类图
-
JDK-ArrayList
public interface List<E> extends Collection<E> { Iterator<E> iterator(); } public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } }
-
源码角色分析
注意事项
-
提供了一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以以遍历对象
-
隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成
-
提供了一种设计思想,就是一个类应该只有一个引起变化的原因(单一职责原则)。**在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样当集合改变的时候,只影响到聚合对象。**而如果遍历方式改变也只影响到迭代器
-
当要展示一组相似对象,或者遍历一组相同对象时使用,适合使用迭代器模式
-
缺点是每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类