何为迭代器模式

迭代器模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式是一种行为型设计模式,在 Java 的集合框架中使用到迭代器(Iterator)来遍历集合中的元素。

但是,迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

迭代器模式的类图如下所示。

何为组合模式

组合模式允许你将对象表现组合成树形结构来表现“部分 - 整体”层次结构。组合让客户可以统一处理个别对象和对象组合。组合模式是一种结构型设计模式。

但是,在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

组合模式的类图如下所示。

322609617

示例

在本例子的迭代器模式中,菜单项用的是数组,数组默认没有迭代器,因此我们可以自己使用迭代器来对数组进行遍历,使用了迭代器模式,调用者在取出元素时就不必知道迭代的具体集合是哪一个了。

MenuItem 类如下。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MenuItem {

    private String name;

    private String desc;

    private double price;

}

需要一个 Menu 接口,必须要实现创建迭代器的方法。

public interface Menu {

    /**
     * 创建必须的迭代器
     *
     * @return
     */
    Iterator<MenuItem> createIterator();

}

对菜单接口的实现,同时有一个内部类用于创建迭代器对象,这个迭代器的具体实现不必知道可以为私有。

public class LunchMenu implements Menu {

    MenuItem[] menuItems;
    final int max_size = 10;
    int count = 0;

    public LunchMenu() {
        menuItems = new MenuItem[max_size];

        addItem(new MenuItem("金拱门豪华套餐", "1个,带点番茄酱和黑椒", 35.40));
        addItem(new MenuItem("必败客披萨", "2个,一个榴莲味,一个火腿肠味", 22.13));
        addItem(new MenuItem("可乐", "2瓶,带吸管", 6.00));
    }

    public void addItem(MenuItem menuItem) {
        menuItems[count] = menuItem;
        count++;
    }

    @Override
    public Iterator<MenuItem> createIterator() {
        return new LunchIterator();
    }

    // 迭代器内部类,不必知道具体的迭代器实现
    private class LunchIterator implements Iterator<MenuItem> {

        int length = count;
        int index = 0;

        @Override
        public boolean hasNext() {
            return index < length;
        }

        @Override
        public MenuItem next() {
            MenuItem item = menuItems[index];
            if(item == null) throw new NoSuchElementException("没有元素了");
            index++;
            return item;
        }
    }
}

调用者,服务员。

import java.util.Iterator;

public class Waitress {

    LunchMenu lunchMenu;

    public Waitress() {
    }

    public Waitress(LunchMenu lunchMenu) {
        this.lunchMenu = lunchMenu;
    }

    public void printMenu() {
        printMenu(lunchMenu.createIterator());
    }

    private void printMenu(Iterator<MenuItem> iterator) {
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

}

测试一下

public class IteratorTest {

    public static void main(String[] args) {
        LunchMenu lunchMenu = new LunchMenu();

        Waitress waitress = new Waitress(lunchMenu);
        waitress.printMenu();
    }

}
// ======= 运行结果 =======
// MenuItem(name=金拱门豪华套餐, desc=1个,带点番茄酱和黑椒, price=35.4)
// MenuItem(name=必败客披萨, desc=2个,一个榴莲味,一个火腿肠味, price=22.13)
// MenuItem(name=可乐, desc=2瓶,带吸管, price=6.0)

接下来有一个新的需求,就是菜单又包含着子菜单,如下所示。

  • 菜单 1
    • 菜单 1-1
    • 菜单 1-2

比如 1 个员工(项目经理)要管理多个员工(程序员)。

import java.util.ArrayList;
import java.util.List;
 
public class Employee {
   private String name;
   private String dept;
   private int salary;
   private List<Employee> subordinates;
 
   //构造函数
   public Employee(String name,String dept, int sal) {
      this.name = name;
      this.dept = dept;
      this.salary = sal;
      subordinates = new ArrayList<Employee>();
   }
 
   public void add(Employee e) {
      subordinates.add(e);
   }
 
   public void remove(Employee e) {
      subordinates.remove(e);
   }
 
   public List<Employee> getSubordinates(){
     return subordinates;
   }
 
   public String toString(){
      return "Employee :[ Name : "+ name 
      +", dept : "+ dept + ", salary :"
      + salary+" ]";
   }   
}

创建和打印员工

public class CompositePatternDemo {
   public static void main(String[] args) {
      Employee CEO = new Employee("John","CEO", 30000);
 
      Employee headSales = new Employee("Robert","Head Sales", 20000);
 
      Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
 
      Employee clerk1 = new Employee("Laura","Marketing", 10000);
      Employee clerk2 = new Employee("Bob","Marketing", 10000);
 
      Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
      Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
 
      CEO.add(headSales);
      CEO.add(headMarketing);
 
      headSales.add(salesExecutive1);
      headSales.add(salesExecutive2);
 
      headMarketing.add(clerk1);
      headMarketing.add(clerk2);
 
      //打印该组织的所有员工
      System.out.println(CEO); 
      for (Employee headEmployee : CEO.getSubordinates()) {
         System.out.println(headEmployee);
         for (Employee employee : headEmployee.getSubordinates()) {
            System.out.println(employee);
         }
      }        
   }
}

运行一下

Employee :[ Name : John, dept : CEO, salary :30000 ]
Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
Employee :[ Name : Richard, dept : Sales, salary :10000 ]
Employee :[ Name : Rob, dept : Sales, salary :10000 ]
Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
Employee :[ Name : Bob, dept : Marketing, salary :10000 ]