美文网首页
chapter09_管理良好的集合——迭代器与组合模式

chapter09_管理良好的集合——迭代器与组合模式

作者: 米都都 | 来源:发表于2019-01-07 18:53 被阅读0次
    • 迭代器可以让客户遍历集合但无法窥视内部对象存储的方式

    • (1) 不使用迭代器会让遍历操作无法统一接口

        public static void printMenu() {
      
            PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
            DinerMenu dinerMenu = new DinerMenu();
      
            ArrayList<MenuItem> breakfastItems = pancakeHouseMenu.getMenuItems();
            MenuItem[] lunchItems = dinerMenu.getMenuItems();
      
            // Exposing implementation
            System.out.println("USING FOR LOOPS");
        
            for (int i = 0; i < breakfastItems.size(); i++) {
      
                MenuItem menuItem = (MenuItem) breakfastItems.get(i);
                System.out.print(menuItem.getName());
                System.out.println("\t\t" + menuItem.getPrice());
                System.out.println("\t" + menuItem.getDescription());
            }
      
            for (int i = 0; i < lunchItems.length; i++) {
      
                MenuItem menuItem = lunchItems[i];
                System.out.print(menuItem.getName());
                System.out.println("\t\t" + menuItem.getPrice());
                System.out.println("\t" + menuItem.getDescription());
            }
        }
      

      (2) 使用迭代器便于统一接口

        public void printMenu() {
      
            Iterator pancakeIterator = pancakeHouseMenu.createIterator();
            Iterator dinerIterator = dinerMenu.createIterator();
      
            System.out.println("MENU\n----\nBREAKFAST");
            printMenuHelper(pancakeIterator);
      
            System.out.println("\nLUNCH");
            printMenuHelper(dinerIterator);
        }
      
        private void printMenuHelper(Iterator iterator) {
      
            while (iterator.hasNext()) {
      
                MenuItem menuItem = iterator.next();
            
                System.out.print(menuItem.getName() + ", ");
                System.out.print(menuItem.getPrice() + " -- ");
                System.out.println(menuItem.getDescription());
            }
        }
      
    • 迭代器中一般包含两个方法

        public interface Iterator {
      
            boolean hasNext();
      
            MenuItem next();
        }
      

      一种内部是数组的迭代器的实现

        public class DinerMenuIterator implements Iterator {
      
            private MenuItem[] items;
            private int position = 0;
      
            public DinerMenuIterator(MenuItem[] items) {
      
                this.items = items;
            }
      
            public MenuItem next() {
      
                MenuItem menuItem = items[position];
                position = position + 1;
        
                return menuItem;
            }
      
            public boolean hasNext() {
      
                if (position >= items.length || items[position] == null) {
                    return false;
                } else {
                    return true;
                }
            }
        }
      

      这样, 只需在遍历集合前创建对应的迭代器即可

        public Iterator createIterator() {
            return new DinerMenuIterator(menuItems);
        }
      
    • Java本身提供了Iterator接口

        public interface Iterator<E> {
      
            boolean hasNext();
      
            E next();
      
            default void remove() {
                throw new UnsupportedOperationException("remove");
            }
      
            default void forEachRemaining(Consumer<? super E> action) {
         
                Objects.requireNonNull(action);
         
                while (hasNext())
                    action.accept(next());
            }
        }
      

      因此, Java的集合类一般都提供了产生迭代器的方法

      ArrayList.java

        public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
      
            ...
      
            public Iterator<E> iterator() {
                return new Itr();
            }
      
            ...
      
        }
      

      Iterator()方法中, 产生了一个ArrayList的内部类的对象Itr

        public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
      
            ...
      
            private class Itr implements Iterator<E> {
      
                ...
            }
      
            ...
        }
      
    • 迭代器模式

      提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示

    • 设计原则: 单一责任原则

      一个类应该只有一个引起变化的原因

      例如在没有使用迭代器以前, 一个集合类既要维持内部的数据结构, 又要提供遍历访问操作, 就有了多重的责任; 现在使用迭代器将遍历的责任交给其他的类


    • (1) 当集合中的对象内部又嵌套了集合对象时, 在不使用任何设计模式的情况下, 会导致在遍历集合的时候, 需要单独判断当前对象的类型再做操作

      (2) 为了解决(1)中的问题, 可以定义一个超类, 让单个对象和对象集合都继承这个超类;

      在超类中定义抽象方法, 然后由单个对象的类和对象集合类实现;

      这样, 整个就会组织成一个树形结构, 可以容纳菜单(超类)、子菜单(对象集合)、菜单项(单个对象)

      (3) 示例

      MenuComponent.java

        public abstract class MenuComponent {
      
            public void add(MenuComponent menuComponent) {
      
                throw new UnsupportedOperationException();
            }
      
            public void remove(MenuComponent menuComponent) {
      
                throw new UnsupportedOperationException();
            }
      
            public MenuComponent getChild(int i) {
      
                throw new UnsupportedOperationException();
            }
      
            public String getName() {
      
                throw new UnsupportedOperationException();
            }
      
            public String getDescription() {
      
                throw new UnsupportedOperationException();
            }
      
            public double getPrice() {
      
                throw new UnsupportedOperationException();
            }
      
            public boolean isVegetarian() {
      
                throw new UnsupportedOperationException();
            }
      
            public void print() {
      
                throw new UnsupportedOperationException();
            }
        }
      

      MenuComponent是一个超类, 定义了一系列默认方法的实现, 这些实现中都会抛出UnsupportedOperationException异常;

      MenuItem.java

        public class MenuItem extends MenuComponent {
      
            private String name;
            private String description;
            private boolean vegetarian;
            private double price;
      
            public MenuItem(String name, String description,
            boolean vegetarian, double price) {
      
                this.name = name;
                this.description = description;
                this.vegetarian = vegetarian;
                this.price = price;
            }
      
            public String getName() {
                return name;
            }
      
            public String getDescription() {
                return description;
            }
      
            public double getPrice() {
                return price;
            }
      
            public boolean isVegetarian() {
                return vegetarian;
            }
      
            public void print() {
      
                System.out.print("  " + getName());
        
                if (isVegetarian()) {
                    System.out.print("(v)");
                }
      
                System.out.println(", " + getPrice());
                System.out.println("     -- " + getDescription());
            }
        }
      

      MenuItem是具体的组件类, 它实现了它可以实现的方法, 调用它未实现的方法就会调用它的基类的方法从而抛出异常

      Menu.java

        public class Menu extends MenuComponent {
      
            private ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
            private String name;
            private String description;
      
            public Menu(String name, String description) {
      
                this.name = name;
                this.description = description;
            }
      
            public void add(MenuComponent menuComponent) {
      
                menuComponents.add(menuComponent);
            }
      
            public void remove(MenuComponent menuComponent) {
      
                menuComponents.remove(menuComponent);
            }
      
            public MenuComponent getChild(int i) {
      
                return menuComponents.get(i);
            }
      
            public String getName() {
      
                return name;
            }
      
            public String getDescription() {
      
                return description;
            }
      
            public void print() {
      
                System.out.print("\n" + getName());
                System.out.println(", " + getDescription());
                System.out.println("---------------------");
      
                Iterator<MenuComponent> iterator = menuComponents.iterator();
      
                while (iterator.hasNext()) {
                    MenuComponent menuComponent = iterator.next();
                    menuComponent.print();
                }
            }
        }
      

      Menu是菜单类, 它内部包含一个存储MenuComponent的集合, 在print()方法中, 会调用内部MenuComponent的print()方法

    • 组合模式

      将对象组合成树形结构来表现整体/部分层次结构。 组合可以让客户以一致的方式处理个别对象以及对象组合

    • (1) 组合模式保证了透明性: 客户在操作是将组合对象和叶结点一视同仁, 一个元素是组合对象还是叶结点对客户是透明

      (2) 保证透明性的同时产生了安全性问题, 因为调用时很可能会调用抛出UnsupportedException的方法。 解决方法是将组合对象和叶结点定义成不同接口, 用instanceof判断;

      但是, 这样又丧失了透明性.

      所以, 组合模式就是透明性和安全性的折中

      (3) 为啥要把组合模式和迭代器模式放在一起呢?

      因为组合模式在需要遍历集合的时候, 也会使用迭代器

    相关文章

      网友评论

          本文标题:chapter09_管理良好的集合——迭代器与组合模式

          本文链接:https://www.haomeiwen.com/subject/idrprqtx.html