"Head First Design Patterns" notas de estudo - padrão iterator

Deixe-nos atravessar a matriz de clientes, pilha, lista ou tabela hash, você não pode saber a forma como armazenar os objetos, contamos hoje, o padrão de iterador.

caso

Nós temos dois restaurantes para operações de mesclagem, seus pratos têm em comum, ambos classe da loja precisa de um comuns propriedades do menu, criamos um menu de classe separada, como se segue.

public class MenuItem {
    String name;
    String description;
    boolean vegetarian;
    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 boolean isVegetarian() {
        return vegetarian;
    }

    public double getPrice() {
        return price;
    }
}

Agora olhe para dois Categoria da loja.

public class DinerMenu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;

    public DinerMenu() {
        menuItems = new MenuItem[MAX_ITEMS];

        addItem("Vegetarian BLT",
                "(Fakin') Bacon with lettuce & tomato on whole wheat",
                true,
                2.99);
        addItem("BLT",
                "Bacon with lettuce & tomato on whole wheat",
                false,
                2.99);
        addItem("Soup of the day",
                "Soup of the day, with a side of potato salad",
                false,
                3.29);
        addItem("Hotdog",
                "A hot dog, with saurkraut, relish, onions, toped with cheese",
                false,
                3.05);
    }

    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("Sorry, menu is full! Can't add item to menu");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    public MenuItem[] getMenuItems() {
        return menuItems;
    }
}

public class PancakeHouseMenu {
    ArrayList menuItems;

    public PancakeHouseMenu() {
        menuItems = new ArrayList();
        addItem("K&B's Pancake Breakfast",
                "Pancakes with scrambled eggs, and toast",
                true,
                2.99);
        addItem("Regular Pancake Breakfast",
                "Pancakes with fried eggs, sausage",
                false,
                2.99);
        addItem("Blueberry Pancakes",
                "Pancakes made with fresh blueberries",
                true,
                3.49);
        addItem("Waffles",
                "Waffles, with your choice of blueberries or strawberries",
                true,
                3.59);
    }

    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.add(menuItem);
    }

    public ArrayList getMenuItems() {
        return menuItems;
    }
}

A estrutura é semelhante, há uma propriedades do menu, mas é um conjunto de uma matriz, adicionar alguns pratos, bem como um retorno ao menu de getter método () durante a inicialização.

Seguinte é o principal evento que temos de operar, classe garçonete, existem métodos para menu de impressão.

public class Waitress {

    public void printMenu() {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();

        ArrayList houseMenuMenuItems = pancakeHouseMenu.getMenuItems();
        MenuItem[] dinerMenuMenuItems = dinerMenu.getMenuItems();

        // 循环遍历
        for (int i = 0; i < houseMenuMenuItems.size(); i++) {
            MenuItem menuItem = (MenuItem) houseMenuMenuItems.get(i);
            System.out.println(menuItem.getName() + " ");
            System.out.println(menuItem.getPrice() + " ");
            System.out.println(menuItem.getDescription());
        }

        for (int i = 0; i < dinerMenuMenuItems.length; i++) {
            MenuItem dinerMenuMenuItem = dinerMenuMenuItems[i];
            System.out.println(dinerMenuMenuItem.getName() + " ");
            System.out.println(dinerMenuMenuItem.getPrice() + " ");
            System.out.println(dinerMenuMenuItem.getDescription());
        }
    }
}

Este é o mais fácil de usar para itera de loop, se temos uma nova loja para a união loja, temos de continuar a aumentar por iteração de loop Neste método, é repetição muito redundante, devemos mudar a parte do pacote, usaremos iterator padrão para melhorar. Em primeiro lugar, criar uma interface iterador.

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

Em seguida, criar colecções classe iteração separadas e matrizes, eles alcançam os métodos acima, um é julgado se ainda existe um método () retorna a próxima é o seguinte elemento () elemento hasNext.

public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;

    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }

    @Override
    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public Object next() {
        MenuItem menuItem = items[position];
        position += 1;
        return menuItem;
    }
}

public class PancakeHouseMenuIterator implements Iterator {
    ArrayList items;
    int position = 0;

    public PancakeHouseMenuIterator(ArrayList items) {
        this.items = items;
    }

    @Override
    public boolean hasNext() {
        if (position >= items.size() || items.get(position) == null) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public Object next() {
        MenuItem menuItem = (MenuItem)items.get(position);
        position += 1;
        return menuItem;
    }
}

Em seguida, modificar a categoria dois menus método, getMenuItems Delete (), porque ele iria expor alcançar o nosso código interno, e depois adicionar um método retorna um iterador, percorremos dados através deste iterador.

public class DinerMenu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;

    public DinerMenu() {
        menuItems = new MenuItem[MAX_ITEMS];

        addItem("Vegetarian BLT",
                "(Fakin') Bacon with lettuce & tomato on whole wheat",
                true,
                2.99);
        addItem("BLT",
                "Bacon with lettuce & tomato on whole wheat",
                false,
                2.99);
        addItem("Soup of the day",
                "Soup of the day, with a side of potato salad",
                false,
                3.29);
        addItem("Hotdog",
                "A hot dog, with saurkraut, relish, onions, toped with cheese",
                false,
                3.05);
    }

    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("Sorry, menu is full! Can't add item to menu");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }
}

public class PancakeHouseMenu {
    ArrayList menuItems;

    public PancakeHouseMenu() {
        menuItems = new ArrayList();
        addItem("K&B's Pancake Breakfast",
                "Pancakes with scrambled eggs, and toast",
                true,
                2.99);
        addItem("Regular Pancake Breakfast",
                "Pancakes with fried eggs, sausage",
                false,
                2.99);
        addItem("Blueberry Pancakes",
                "Pancakes made with fresh blueberries",
                true,
                3.49);
        addItem("Waffles",
                "Waffles, with your choice of blueberries or strawberries",
                true,
                3.59);
    }

    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.add(menuItem);
    }

    public Iterator creatorIterator() {
        return new PancakeHouseMenuIterator(menuItems);
    }
}

A última é a nossa classe garçonete, e criar um método particular para os dados de atravessar o uso de iteradores, e em seguida, modificar o menu de impressão, utilizando creatorIterator apenas a () retorna um iterador, com métodos privados atravessar dados.

public class Waitress {

    public void printMenu() {
        DinerMenu dinerMenu = new DinerMenu();
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        Iterator dinerIterator = dinerMenu.createIterator();
        Iterator pancakeIterator = pancakeHouseMenu.creatorIterator();
        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(dinerIterator);
        System.out.println("\nLUNCH");
        printMenu(pancakeIterator);
    }

    private void printMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            System.out.println(menuItem.getName() + " ");
            System.out.println(menuItem.getPrice() + " -- ");
            System.out.println(menuItem.getDescription());
        }
    }
}

Nós já não precisa método getMenuItem (), suprimido, substituído iteração objecto é o de obter, e, em seguida, usar o método seguinte (Repetidor iteração) printMenu.

Nós só precisamos dar-lhes dois iteradores, em seguida, cada loja aumenta um método que retorna o objeto iterador sobre ele. A nossa garçonete era tão fácil expansão e manutenção, quando a nova loja, a loja só precisa criar um objeto, ele retorna um iterador, chame printMenu método (Iterator iterator).

Este iterator nos permite descolar do garçonete alcançar classe específica, ela não precisa saber quais dados são usados ​​na estrutura do menu, contanto que ela pode ficar a conhecer iterators pode. Iteração nos permite percorrer cada elemento na polimerização, em vez de ter de implementar transversal dentro do método, deixe-nos ter acesso a todos os elementos em agregação de dados, nós encapsular travessia.

Continuamos a melhorar a nossa concepção, de fato, ArrayList tem proporcionado um método para a obtenção de Iterator para nós, por isso modificar PancakeHouseMenu de createIterator () método, primeiro java.util.Iterator importação, vamos usar a interface do iterador fornecido pelo Java.

public Iterator creatorIterator() {
        return menuItems.iterator();
    }

Aqui nós modificar DinerMenu, para atender às necessidades de interface de java.util.Iterator, que requer modificações do DinerMenuIterator início. Apresentando java.util.Iterator, atingir método remove ().

public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;

    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }

    @Override
    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public Object next() {
        MenuItem menuItem = items[position];
        position += 1;
        return menuItem;
    }

    @Override
    public void remove() {
        if (position <= 0) {
            throw new IllegalStateException("You can't remove an item until you've done at least one next()");
        }
        if (items[position - 1] != null) {
            for (int i = position - 1; i < items.length - 1; i++) {
                items[i] = items[i+1];
            }
            items[items.length-1] = null;
        }
    }
}

DinerMenu então adicionado no java.util.Iterator introdução. Nós também pode adicionar uma interface de menu make duas classes menu do restaurante que implementa essa interface, método conveniente que chamamos a classe empregada, por isso estamos orientado interface de programação, reduzindo o acoplamento e realização concreta da classe empregada.

public interface Menu {
    public Iterator createIterator();
}

public class DinerMenu implements Menu {...}

public class PancakeHouseMenu implements Menu {...}

Após implementar essa interface, olhamos para a classe empregada.

public class Waitress {

    public void printMenu() {
        Menu dinerMenu = new DinerMenu();
        Menu pancakeHouseMenu = new PancakeHouseMenu();
        Iterator dinerIterator = dinerMenu.createIterator();
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(dinerIterator);
        System.out.println("\nLUNCH");
        printMenu(pancakeIterator);
    }

    private void printMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            System.out.println(menuItem.getName() + " ");
            System.out.println(menuItem.getPrice() + " -- ");
            System.out.println(menuItem.getDescription());
        }
    }
}

Import java.util.Iterator, utilize o menu declarou categoria dois menus, em vez de uma classe concreta, "para a programação de interface, em vez de programação." Podemos reduzir a dependência entre a garçonete e classes concretas.

Iterator definição padrão

modo iterativo fornece um método sequencial para cada elemento de um objecto polimérico, sem mostrar o seu interior é exposto.

Iterator padrão nos permite percorrer cada elemento no conjunto de dados, e não expor sua estrutura de dados, ea responsabilidade para atravessar os elementos iterator, em vez de objetos agregados, o que torna a interface e agregação implementação torna-se mais conciso , mas também permite que ele seja mais focada em tarefas de agregação, e ignorar as coisas que os dados transversais.

: "Single responsabilidade" princípio de design motivo para uma classe deve ser apenas uma causa mudança.

Você deve evitar alterar a classe, porque é fácil de modificar o código causou muitos erros potenciais. Se uma classe tem duas razões para a mudança, então a probabilidade de esse tipo de mudança vai subir, e quando ele realmente mudou, sendo que ambos serão afetados, por isso siga este princípio, apenas para atribuir a responsabilidade de uma classe.

Devemos aprender a distinguir é da responsabilidade do projeto, é muito difícil olhar para o comportamento de um grande grupo, em seguida, concentrar-los juntos, mesmo que eles podem pertencer a dois ou mais diferentes responsabilidades, mas estamos trabalhando incansavelmente inspeção próprio projeto, como o sistema cresce, a razão nós sempre observar uma mudança de classe, se houver mais de um.

New Cafe

Agora queremos adicionar um café em nosso sistema, em seguida, como projetá-lo?

public class CafeMenu implements Menu {
    Hashtable menuItems = new Hashtable();

    public CafeMenu() {
        addItem("Veggie Burger and Air Fries",
                "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
                true,
                3.99);
        addItem("Soup of the day",
                "A cup of the soup of the day, with a side salad",
                false,
                3.69);
        addItem("Burrito",
                "A large burrito, with whole pinto beans, salsa, guacamole",
                true,
                4.29);
    }

    public void addItem(String name, String description, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.put(menuItem.getName(), menuItem);
    }

    @Override
    public Iterator createIterator() {
        return menuItems.values().iterator();
    }
}

Esta é a classe menu de café, e as duas primeiras classes são semelhantes menus, interfaces de menu são realizados, retorna um iterador. Em seguida, o método garçonete classe printMenu () para adicionar algumas linhas, para criar um menu como o café, obter um iterador, chame o método printMenu (Iterator iterator) através dos dados.

public void printMenu() {
        Menu dinerMenu = new DinerMenu();
        Menu pancakeHouseMenu = new PancakeHouseMenu();
        CafeMenu cafeMenu = new CafeMenu();
        Iterator dinerIterator = dinerMenu.createIterator();
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator cafeMenuIterator = cafeMenu.createIterator();
        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(dinerIterator);
        System.out.println("\nLUNCH");
        printMenu(pancakeIterator);
        System.out.println("\nDINNER");
        printMenu(cafeMenuIterator);
    }

Isso completa a finalidade de adicionar um novo menu, mas há um problema, o programa chama vezes printMenu (), não é bonito, e cada menu recém-adicionado, mas também abrir a garçonete para adicionar mais códigos de classe como podemos modificar o design? Olhe para o código:

public class Waitress {

    ArrayList menus;

    public Waitress(ArrayList menus) {
        this.menus = menus;
    }

    public void printMenu() {
        Iterator iterator = menus.iterator();
        while (iterator.hasNext()) {
            Menu next = (Menu) iterator.next();
            printMenu(next.createIterator());
        }
    }

    private void printMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            System.out.println(menuItem.getName() + " ");
            System.out.println(menuItem.getPrice() + " -- ");
            System.out.println(menuItem.getDescription());
        }
    }
}

Faça uma casa de menu coleção classe, quando passaram um conjunto de depuração só para dar um menu Objeto garçonete, e, em seguida, percorrer a coleção em printMenu () método permite código mais simples.

Agora eles querem seguido por uma sobremesa de "sub-menu." Um pouco semelhante a uma estrutura de árvore, não podemos atribuir o cardápio de sobremesas para itens variedade de menus, por isso têm de modificar! Modificar ver o próximo blog.

Publicado 26 artigos originais · ganhou elogios 2 · Vistas 2319

Acho que você gosta

Origin blog.csdn.net/qq_42909545/article/details/105024998
Recomendado
Clasificación