从王者荣耀看设计模式(迭代器模式)
一.简介
王者荣耀是一款支持多人协同竞技的游戏,支持QQ/微信登陆。在王者荣耀中,可以通过游戏列表查看QQ/微信好友的状态,以便判断是否邀请好友加入游戏
二.模式动机
一个聚合对象,应该提供一种方法让别人可以访问它的元素,而又不需要暴露它的内部结构。此外,针对不同的需要,可能要以不同的方式遍历整个聚合对象,但是我们并不希望在聚合对象的抽象层接口充斥着不同遍历的操作。
怎样遍历一个聚合对象,又不需要了解聚合对象的内部结构,还能够提供多种不同的遍历方式。这就是迭代器模式要解决的问题。假设在上图中在线状态的玩家信息在系统内部以数组形式存储,离线玩家信息以集合形式存储,可以通过
创建两种迭代器模式给用户提供统一的接口。
三.迭代器模式
迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor).迭代器模式是一种对象行为型模式。
- 迭代器模式的使用场景
- 访问一个聚合对象的内容而无须暴露它的内部表示。将聚合对象的访问与内部数据的存储分离,使得访问聚合对象时无须了解其内部实现细节
- 需要为聚合对象提供多种遍历方式
- 为遍历不同的聚合结构提供一个统一的接口。当需要扩展聚合结构或者给聚合结构增加新的遍历方式时可以使用迭代器模式,它提供了聚合结构和迭代器的抽象定义
- 迭代器模式涉及的设计原则有:
- 为了交互对象之间的松耦合而努力
- 一个类应该只有一个引起变化的原因
- 针对接口编程,而不是针对实现编程
-
迭代器模式的通用类图
-
迭代器模式所涉及的角色有:
● Iterator(抽象迭代器类):抽象迭代器定义了访问和遍历元素的接口,一般声明以下方法:用于获取第一元素的first(),用于访问下一个元素的next(),用于判断是否还有下一个元素的hasNext(),用于获取当前元素的currentItem(),在其子类中将实现这些方法
● ConcreteIterator(具体迭代器类):具体迭代器实现了抽象迭代器接口,完成对聚合对象的遍历,同时在对聚合对象进行遍历时跟踪其当前位置
● Aggregate(抽象聚合类):抽象聚合类用于存储对象,并定义创建相应迭代器的接口,声明一个createIterator()方法用于创建一个迭代器对象
● ConcreteAggregate(具体聚合类):具体聚合类实现了创建相应迭代器的接口,实现了在聚合类中声明的createIterator()方法,该方法返回一个与该聚合相应的具体迭代器ConcreteIterator实例 -
迭代器模式的优点
- 它支持以不同的方式遍历一个聚合对象。对于复杂的聚合对象可用多种方法来进行遍历,在迭代器模式中只需要用一个不同的迭代器来替换原有迭代器即可改变遍历算法,也可以自己定义迭代器的子类以支持新的遍历方式
- 迭代器简化了聚合类。因为引入了迭代器。在原有的聚合对象中不需要再自行提供遍历等数据操作方法,这样可以简化聚合类的设计
- 在同一个聚合中可以有多个遍历。 由于每个迭代器都保持自己的遍历状态,因此可以同时对一个聚合对象进行多个遍历操作
- 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足"开闭原则"
- 迭代器模式的缺点
由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性
四.结构图
五.设计类图
六.代码实现
Iterator(抽象迭代器类)
package com.practice.Iterator;
/*
* Iterater类,定义了访问和遍历元素的接口
*/
public interface Iterator {
void setPlayer(int i); //设置为当前玩家
void next(); //访问下一个玩家信息
void previous(); //访问前一个玩家信息
boolean isLast(); //判断当前玩家是否为末位玩家
Object currentPlayer(); //返回当前玩家信息
boolean isFirst(); //判断当前玩家是否为首位玩家
int getNumber(); //总共有多少玩家
}
OfflinePlayer(ConcreteIterator类)
package com.practice.ConcreteIterator;
import com.practice.ConcreteAggregate.OfflinePlayer;
import com.practice.ConcreteAggregate.PlayerInfor;
import com.practice.Iterator.Iterator;
/*
* ConcreteIterator类:实现抽象迭代器的接口,完成对聚合对象的遍历
* @playerinfor:OfflinePlayer对象,通过getPlayerItems方法得到数组对象
* @playerItems:PlayerInfor:存储玩家信息的数组
*/
public class OfflinePlayerIterator implements Iterator {
OfflinePlayer playerinfor;
PlayerInfor [] playerItems;
private int position = 0;
public OfflinePlayerIterator() {
playerinfor = new OfflinePlayer();
playerItems = playerinfor.getPlayerItems();
}
public void setPlayer(int i) {
position = i;
}
public void next() {
if(position < playerItems.length) {
position++;
}
}
public void previous() {
if(position > 0) {
position--;
}
}
public boolean isLast() {
return position == playerItems.length;
}
public Object currentPlayer() {
return playerItems[position];
}
public boolean isFirst() {
return position == 0;
}
public int getNumber() {
return playerItems.length;
}
}
OnlinePlayerIterator(ConcreteIterator类)
package com.practice.ConcreteIterator;
import java.util.ArrayList;
import com.practice.ConcreteAggregate.OnlinePlayer;
import com.practice.ConcreteAggregate.PlayerInfor;
import com.practice.Iterator.Iterator;
/*
* ConcreteIterator类:实现抽象迭代器的接口,完成对聚合对象的遍历
* @playerItems:玩家信息项集合
* @palyers:OnlinePlayerIterator对象,通过players得到集合信息
*/
public class OnlinePlayerIterator implements Iterator {
ArrayList<PlayerInfor>playerItems;
OnlinePlayer players;
private int currentIndex = 0;
public OnlinePlayerIterator() {
players = new OnlinePlayer();
playerItems = players.getPlayerItems();//得到OnlinePlayer对象中的集合
}
public void setPlayer(int i) {
currentIndex = i;
}
public void next() { //访问集合中的下一个元素
if(currentIndex < playerItems.size()) {
currentIndex ++;
}
}
public void previous() {
if(currentIndex > 0) {
currentIndex --;
}
}
public boolean isLast() {
return currentIndex == playerItems.size();
}
public Object currentPlayer() {
return playerItems.get(currentIndex);
}
public boolean isFirst() {
return currentIndex == 0;
}
public int getNumber() {
return playerItems.size();
}
}
Player(Aggregate类)
package com.practice.Aggregate;
import com.practice.Iterator.Iterator;
/*
* Aggregate类,声明createIterator()方法用于一个迭代器对象
*/
public interface Player {
Iterator createIterator(); //返回一个迭代器类型
}
OfflinePlayer(ConcreteAggregate类)
package com.practice.ConcreteAggregate;
import com.practice.Aggregate.Player;
import com.practice.ConcreteIterator.OfflinePlayerIterator;
import com.practice.Iterator.Iterator;
/*
* ConcreteAggregate类:创建相应迭代器的接口,实现createIterater用于创建一个迭代器对象
* PlayerItems:数组,用于存放PlayerInfor类型的玩家信息数据
* @MAX_ITEMS 定义数组的长度
*/
public class OfflinePlayer implements Player {
static final int MAX_ITEMS = 5;
int numberOfItems = 0;
PlayerInfor [] playerItems;
public OfflinePlayer() {
playerItems = new PlayerInfor[MAX_ITEMS];
addItem("孙七","永恒钻石III","美团骑手牛笔","离线");
addItem("周八","","胡桃……泽","离线");
addItem("吴九","至尊星耀V","憨批滚吧你","离线");
addItem("郑十","至尊星耀I","北楚","离线");
addItem("邱十一","荣耀黄金I","蒸血-Stalk","离线");
}
public void addItem(String name,String description,String gameName,String status) {
PlayerInfor playerItem = new PlayerInfor(name,description,gameName,status);
if(numberOfItems >= MAX_ITEMS) {
System.out.println("数组越界");
}else {
playerItems[numberOfItems] = playerItem;
numberOfItems = numberOfItems + 1;
}
}
public PlayerInfor[] getPlayerItems() {
return playerItems;
}
public Iterator createIterator() {
return new OfflinePlayerIterator();
}
}
OnlinePlayer(ConcreteAggregate类)
package com.practice.ConcreteAggregate;
import java.util.ArrayList;
import com.practice.Aggregate.Player;
import com.practice.ConcreteIterator.OnlinePlayerIterator;
import com.practice.Iterator.Iterator;
/*
* ConcreteAggregate类:创建相应迭代器的接口,实现createIterater用于创建一个迭代器对象
* @playerItems 定义集合,用于存放PlayerInfor对象
*/
public class OnlinePlayer implements Player{
ArrayList<PlayerInfor> playerItems;
public OnlinePlayer() {
playerItems = new ArrayList<PlayerInfor>();
addItem("张三","至尊星耀III","长发为君留","开局16分钟");
addItem("李四","尊贵铂金II","Z三七J","开局14分钟");
addItem("王五","永恒钻石IV","可爱可爱O","开局10分钟");
addItem("赵六","","TANGIAMIN","开局2分钟");
}
private void addItem(String name, String description, String gameName, String status) {
PlayerInfor playInfor = new PlayerInfor(name,description,gameName,status);
playerItems.add(playInfor);
}
public ArrayList<PlayerInfor> getPlayerItems() {
return playerItems;
}
public Iterator createIterator() {
return new OnlinePlayerIterator();
}
}
PlayerInfor(封装类)
package com.practice.ConcreteAggregate;
/*
* tools类,封装玩家的信息
* @name 玩家的名字
* @description 玩家的游戏段位
* @gameName 玩家在游戏中的名字
* @status 玩家的状态
*/
public class PlayerInfor {
String name;
String description;
String gameName;
String status;
public PlayerInfor(String name,String description,String gameName,String status) {
this.name = name;
this.description = description;
this.gameName = gameName;
this.status = status;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getGameName() {
return gameName;
}
public String getStatus() {
return status;
}
}
Desktop(外观类)
package com.practice.Client;
import com.practice.Aggregate.Player;
import com.practice.ConcreteAggregate.PlayerInfor;
import com.practice.Iterator.Iterator;
/*
* 外观类,向用户提供接口供用户使用
* @onlinePlayer 用集合实现的ConcreteAggregate类
* @offlinePlayer 用数组实现的ConcreteAggregate类
*/
public class Desktop {
Player onlinePlayer;
Player offlinePlayer;
public Desktop(Player onlinePlayer2,Player offlinePlayer2) {
this.onlinePlayer = onlinePlayer2;
this.offlinePlayer = offlinePlayer2;
}
public void display() {
//调用onlinePlayerIterator迭代器
Iterator onlinePlayIterator = onlinePlayer.createIterator();
//调用offlinePlayerIterator迭代器
Iterator offlinePlayIterator = offlinePlayer.createIterator();
System.out.println("---在线玩家- - -");
while(!onlinePlayIterator.isLast()) {
PlayerInfor infor = (PlayerInfor) onlinePlayIterator.currentPlayer();//访问当前玩家信息
System.out.printf("%-15s",infor.getGameName());
System.out.printf("%-15s",infor.getName());
System.out.printf("%-15s",infor.getDescription());
System.out.printf("%-15s",infor.getStatus());
onlinePlayIterator.next();//跳转下一玩家信息
System.out.println();
}
System.out.println("---离线玩家- - -");
while(!offlinePlayIterator.isLast()) {
PlayerInfor infor = (PlayerInfor) offlinePlayIterator.currentPlayer();
System.out.printf("%-15s",infor.getGameName());
System.out.printf("%-15s",infor.getName());
System.out.printf("%-15s",infor.getDescription());
System.out.printf("%-15s",infor.getStatus());
offlinePlayIterator.next();
System.out.println();
}
}
}
PlayerTest(测试类)
package com.practice.Client;
import com.practice.Aggregate.Player;
import com.practice.ConcreteAggregate.OfflinePlayer;
import com.practice.ConcreteAggregate.OnlinePlayer;
/*
* 测试类
*/
public class PlayerTest {
public static void main(String [] args) {
Player onlinePlayer = new OnlinePlayer(); //集合实现迭代器
Player offlinePlayer = new OfflinePlayer(); //数组实现迭代器
Desktop display = new Desktop(onlinePlayer,offlinePlayer);
display.display();
}
}