-
设计模式读书笔记-----迭代器模式
添加时间:2013-8-12 点击量:      你项目组接到一个项目:对电视机的电视频道、电影和收音机菜单进行同一经管,建树一个同一的菜单经管界面,可以或许看到所有的电视界面、电影界面和收音机频道。你有三个手下:小李子、小杏子、小安子,他们分别就每个模块做开辟工作,看他们都做了哪些工作。
      这是主菜单JavaBean,用于显示每个模块的菜单。
public class MenuItem {
private String name;
private String description;
private int channe;
public MenuItem(int channe,String name,String description){
this.name = name;
this.description = description;
this.channe = channe;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getChanne() {
return channe;
}
public void setChanne(int channe) {
this.channe = channe;
}
}
      小李子负责电视频道菜单的实现。他是应用List实现的,他认为如许就可以很是便利的扩大菜单。
public class TVChanneMenu implements TelevisionMenu{
List<MenuItem> menuItems;
/
机关函数完成初始化
/
public TVChanneMenu(){
menuItems = new ArrayList<MenuItem>();
addItem(1, "CCTV-1", "This is CCTV-1");
addItem(2, "CCTV-2", "This is CCTV-2");
addItem(3, "CCTV-3", "This is CCTV-3");
addItem(4, "CCTV-4", "This is CCTV-4");
addItem(5, "CCTV-5", "This is CCTV-5");
}
/
@desc 将电视频道节目添加菜单凑集中
@param channe 频道
@param name 名称
@param description 描述
@return void
/
public void addItem(int channe,String name,String description){
MenuItem tvMenuItem = new MenuItem(channe, name, description);
menuItems.add(tvMenuItem);
}
public List<MenuItem> getMenuItems() {
return menuItems;
}
}
&#160;&#160;&#160;&#160;&#160; 小杏子负责电影菜单模块的开辟。她是应用数组完成的,他认为数组的效力高些,并且可以或许把握菜单的长度。
public class FilmMenu implements TelevisionMenu{
static final int MAX_ITEMS = 5; //菜单最大长度
MenuItem[] menuItems;
int numberOfItems = 0;
/
机关函数完成初始化
/
public FilmMenu(){
menuItems = new MenuItem[MAX_ITEMS];
addItem(1, "绝世天劫", "这是布鲁斯威利斯主演的...");
addItem(2, "达芬奇暗码", "这是我最喜好的电影之一...");
addItem(3, "黑客帝国123", "不知道你可以或许看懂不???");
addItem(4, "我的女友是机械人", "一部我不反感的经典恋情电影...");
addItem(5, "肖申克的救赎", ",幸福,离你有多远");
}
/
@desc 将电影解决添加到菜单项中
@param channe
@param name
@param description
@return void
/
public void addItem(int channe,String name,String description){
MenuItem tvmenuiItem = new MenuItem(channe, name, description);
//断定数组是否越界
if(numberOfItems > MAX_ITEMS){
System.out.println("不好意思,菜单满了....");
}
else{
menuItems[numberOfItems] = tvmenuiItem;
numberOfItems ++;
}
}
public MenuItem[] getMenuItems() {
return menuItems;
}
}
&#160;&#160;&#160;&#160;&#160; 这里就只介绍两个了。他们完成了各自菜单功能的实现,当你在做三个菜单的同一显示时,你必必要要调用他们的getMenuItems(),来取得他们各个菜单里面的值,然则这个时辰题目呈现了,你发明他们的返回值都不雷同,要想显现出来你必须这么干。
List<MenuItem> tvMenuItems = tvMenu.getMenuItems();
for(int i = 0 ; i < tvMenuItems.size() ; i++){
MenuItem menuItem = tvMenuItems.get(i);
............
}
FilmMenu filmMenu = new FilmMenu();
MenuItem[] filmItems = filmMenu.getMenuItems();
for(int i = 0 ; i < filmItems.length ; i++){
MenuItem menuItem = filmItems[i];
............
}
&#160;&#160;&#160;&#160;&#160; 在这里我们老是须要来处理惩罚这个两个菜单,经由过程轮回来遍历这些菜单选项,若是小安子的实现也不合呢?是不是得要三个轮回呢?若是下次有须要增长一个模块呢?在这里你就恼火了,他们为什么不采取雷同的实现体式格式,然则这个时辰你也不成能让他们去更改了,他们有太多的代码在依附着这个两个菜单了,若是更改就意味着要重写很多的代码了。所以你就想是不是可以来封装轮回呢?不错就是封装遍历。这就是迭代器模式的动机--可以或许游走于聚合内的每一个元素,同时还可以供给多种不合的遍历体式格式。
一、模式定义
&#160;&#160;&#160;&#160;&#160; 何谓迭代器模式?所谓迭代器模式就是供给一种办法次序接见一个聚合对象中的各个元素,而不是露出其内部的默示。在实际的开辟过程中,我们可能须要针对不合的需求,可能须要以不合的体式格式来遍历全部整合对象,然则我们不在聚合对象的抽象接口层中充斥着各类不合的便利操纵。这个时辰我们就须要如许一种器材,它应当具备如下三个功能:
&#160;&#160;&#160;&#160;&#160; 1、可以或许便利一个聚合对象。
&#160;&#160;&#160;&#160;&#160; 2、我们不须要懂得聚合对象的内部布局。
&#160;&#160;&#160;&#160;&#160; 3、可以或许供给多种不合的遍历体式格式。
&#160;&#160;&#160;&#160;&#160; 这三个功能就是迭代器模式须要解决的题目。作为一个功能强大的模式,迭代器模式把在元素之间游走的义务交给迭代器,而不是聚合对象。如许做就简化了聚合的接口和实现,也可以让聚合更专注在它所应当专注的工作上,如许做就加倍合适单一义务原则。
二、模式布局
&#160;&#160;&#160;&#160;&#160; 下图是迭代器模式UML图。
&#160;&#160;&#160;&#160;&#160; 从上方可以看书迭代器模式有如下几个角色:
&#160;&#160;&#160;&#160;&#160; Iterator: 抽象迭代器:所有迭代器都须要实现的接口,供给了游走聚合对象元素之间的办法。
&#160;&#160;&#160;&#160;&#160; ConcreteIterator: 具体迭代器。哄骗这个具体的迭代器可以或许对具体的聚合对象进行遍历。每一个聚合对象都应当对应一个具体的迭代器。
&#160;&#160;&#160;&#160;&#160; Aggregate: 抽象聚合类。
&#160;&#160;&#160;&#160;&#160; ConcreteAggregate: 具体聚合类。实现creatorIterator()办法,返回该聚合对象的迭代器。
三、模式实现
&#160;&#160;&#160;&#160; 下面哄骗迭代器模式对上方案例进行优化整改。下面是正对该实例的UML图。
&#160;&#160;&#160;&#160;&#160; 起首我们须要定义迭代器接口。Iterator.java
public interface Iterator {
boolean hasNext();
Object next();
}
&#160;&#160;&#160;&#160;&#160; 然后是我们两个具体的迭代器。一个迭代器遍历电视界面、一个迭代器遍历电影界面。
&#160;&#160;&#160;&#160;&#160; 电影节目标迭代器:FilmMenuIterator.java
public class FilmMenuIterator implements Iterator{
MenuItem[] menuItems;
int position = 0;
public FilmMenuIterator(MenuItem[] menuItems){
this.menuItems = menuItems;
}
public boolean hasNext() {
if(position > menuItems.length-1 || menuItems[position] == null){
return false;
}
return true;
}
public Object next() {
MenuItem menuItem = menuItems[position];
position ++;
return menuItem;
}
}
&#160;&#160;&#160;&#160;&#160; 电视界面的迭代器:TVChanneMenuIterator.java
public class TVChanneMenuIterator implements Iterator{
List<MenuItem> menuItems;
int position = 0;
public TVChanneMenuIterator(List<MenuItem> menuItems){
this.menuItems = menuItems;
}
public boolean hasNext() {
if(position > menuItems.size()-1 || menuItems.get(position) == null){
return false;
}
else{
return true;
}
}
public Object next() {
MenuItem menuItem = menuItems.get(position);
position ++;
return menuItem;
}
}
&#160;&#160;&#160;&#160;&#160; 然后是菜单接口,该接口供给返回具体迭代器的办法:createIterator()。
public interface TelevisionMenu {
public void addItem(int channe,String name,String description);
public Iterator createIrerator();
}
&#160;&#160;&#160;&#160;&#160; 两个具体聚合类。这个两个聚合类实现createIterator()办法,分别返回电视界面的聚合类和电影界面的聚合类。
public class FilmMenu implements TelevisionMenu{
static final int MAX_ITEMS = 5; //菜单最大长度
MenuItem[] menuItems;
int numberOfItems = 0;
/
机关函数完成初始化
/
public FilmMenu(){
menuItems = new MenuItem[MAX_ITEMS];
addItem(1, "绝世天劫", "这是布鲁斯威利斯主演的...");
addItem(2, "达芬奇暗码", "这是我最喜好的电影之一...");
addItem(3, "黑客帝国123", "不知道你可以或许看懂不???");
addItem(4, "我的女友是机械人", "一部我不反感的经典恋情电影...");
addItem(5, "肖申克的救赎", ",幸福,离你有多远");
}
/
@desc 将电影解决添加到菜单项中
@param channe
@param name
@param description
@return void
/
public void addItem(int channe,String name,String description){
MenuItem tvmenuiItem = new MenuItem(channe, name, description);
//断定数组是否越界
if(numberOfItems > MAX_ITEMS){
System.out.println("不好意思,菜单满了....");
}
else{
menuItems[numberOfItems] = tvmenuiItem;
numberOfItems ++;
}
}
public Iterator createIrerator() {
return new FilmMenuIterator(menuItems);
}
}
&#160;
public class TVChanneMenu implements TelevisionMenu{
List<MenuItem> menuItems;
/
机关函数完成初始化
/
public TVChanneMenu(){
menuItems = new ArrayList<MenuItem>();
addItem(1, "CCTV-1", "This is CCTV-1");
addItem(2, "CCTV-2", "This is CCTV-2");
addItem(3, "CCTV-3", "This is CCTV-3");
addItem(4, "CCTV-4", "This is CCTV-4");
addItem(5, "CCTV-5", "This is CCTV-5");
}
/
@desc 将电视频道节目添加菜单凑集中
@param channe 频道
@param name 名称
@param description 描述
@return void
/
public void addItem(int channe,String name,String description){
MenuItem tvMenuItem = new MenuItem(channe, name, description);
menuItems.add(tvMenuItem);
}
public Iterator createIrerator() {
return new TVChanneMenuIterator(menuItems);
}
}
&#160;&#160;&#160;&#160;&#160; 终于完成了,如今就可以来实现主菜单了,用来显现、遍历所有的电视、电影界面咯。
public class MainMenu {
TelevisionMenu tvMenu;
FilmMenu filmMenu;
public MainMenu(TelevisionMenu tvMenu,FilmMenu filmMenu){
this.tvMenu = tvMenu;
this.filmMenu = filmMenu;
}
public void printMenu(){
Iterator tvIterator = tvMenu.createIrerator();
Iterator filmIterator = filmMenu.createIrerator();
System.out.println("电视节目有:");
printMenu(tvIterator);
System.out.println("----------------------------------------------------------------");
System.out.println("电影节目有:");
printMenu(filmIterator);
}
private void printMenu(Iterator iterator) {
while(iterator.hasNext()){
MenuItem menuItem = (MenuItem) iterator.next();
System.out.print("channe:"+menuItem.getChanne()+", ");
System.out.print("name:"+menuItem.getName()+", ");
System.out.println("description :"+menuItem.getDescription());
}
}
}
&#160;&#160;&#160;&#160;&#160; 测试法度:
public class Test {
public static void main(String[] args) {
TVChanneMenu tvMenu = new TVChanneMenu();
FilmMenu filmMenu = new FilmMenu();
MainMenu mainMenu = new MainMenu(tvMenu, filmMenu);
mainMenu.printMenu();
}
}
&#160;&#160;&#160;&#160;&#160; 运行成果
四、模式优毛病
长处
&#160;&#160;&#160;&#160;&#160; 1、它支撑以不合的体式格式遍历一个聚合对象。
&#160;&#160;&#160;&#160;&#160; 2、迭代器简化了聚合类。
&#160;&#160;&#160;&#160;&#160; 3、在同一个聚合上可以有多个遍历。
&#160;&#160;&#160;&#160;&#160; 4、在迭代器模式中,增长新的聚合类和迭代器类都很便利,无须批改原有代码。
毛病
&#160;&#160;&#160;&#160;&#160; 因为迭代器模式将存储数据和遍历数据的职责分别,增长新的聚合类须要对应增长新的迭代器类,类的个数成对增长,这在必然程度上增长了体系的错杂性。
五、模式应用处景
&#160;&#160;&#160;&#160;&#160; 1、接见一个聚合对象的内容而无须露出它的内部默示。
&#160;&#160;&#160;&#160;&#160; 2、须要为聚合对象供给多种遍历体式格式。
&#160;&#160;&#160;&#160;&#160; 3、为遍历不合的聚合布局供给一个同一的接口。
六、模式总结
&#160;&#160;&#160;&#160;&#160; 1、迭代器模式供给一种办法来接见聚合对象,而不消露出这个对象的内部默示。
&#160;&#160;&#160;&#160;&#160; 2、将遍历聚合对象中数据的行动提取出来,封装到一个迭代器中,经由过程专门的迭代器来遍历聚合对象的内部数据,这就是迭代器模式的本质。迭代器模式是“单一职责原则”的完美表现。
&#160;&#160;&#160;&#160;&#160; 3、当应用迭代器的时辰,我们依附聚合供给遍历。
&#160;&#160;&#160;&#160;&#160; 4、迭代器供给了一个通用的接口,让我们遍历聚合的项,放我们编码应用聚合项时,就可以应用多态机制。
文艺不是炫耀,不是花哨空洞的文字堆砌,不是一张又一张的逆光照片,不是将旅行的意义转化为名牌包和明信片的物质展示;很多时候它甚至完全不美——它嘶吼、扭曲,它会痛苦地抽搐,它常常无言地沉默。——艾小柯《文艺是一种信仰》