设计模式之迭代器与组合模式(java)

来源:互联网 发布:tomcat连不上数据库 编辑:程序博客网 时间:2024/04/30 12:13

迭代器模式与组合模式

在这里我们继续引用head first中例子来进行说明:

看看下面饭馆中俩种菜单的实现(一种基于ArrayList,另一种基于数组)

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 double getPrice() {        return price;    }    public boolean isVegetarian() {        return vegetarian;    }}
public class PancakeHouseMenu {    ArrayList menuItems;    public PancakeHouseMenu() {        menuItems = new ArrayList();        addItem("aaa", "description", true, 2.99);        addItem("bbb", "description", true, 2.99);        addItem("ccc", "description", true, 2.99);    }    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;    }    //等等。。}
public class DinerMenu {    static final int MAX_ITEMS = 6;    int numberOfItems = 0;    MenuItem[] menuItems;    public DinerMenu() {        menuItems = new MenuItem[MAX_ITEMS];        addItem("aaa", "description", true, 2.99);        addItem("bbb", "description", true, 2.99);        addItem("ccc", "description", true, 2.99);    }    public void addItem(String name, String description, boolean vegetarian, double price) {        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);        if(numberOfItems > MAX_ITEMS) {            System.out.println("menu已经满了,不能再添加了");        }        else {            menuItems[numberOfItems] = menuItem;            numberOfItems = numberOfItems + 1;        }    }    public MenuItem[] getMenuItems() {        return menuItems;    }}

俩种不同实现原理的菜单,如果我们要定义一个服务员类打印菜单,可能是以下形式:

        for(int i=0; i<breakfastItems.size(); i++) {            MenuItem menuItem = (MenuItem) breakfastItems.get(i);            System.out.println(menuItem.getName());            System.out.println(menuItem.getDescription());            System.out.println(menuItem.getPrice());        }        for(int i=0; i<lunchItems.length; i++) {            MenuItem menuItem = lunchItems[i];            System.out.println(menuItem.getName());            System.out.println(menuItem.getDescription());            System.out.println(menuItem.getPrice());        }        如果有n种菜单,那么上面就要写n种遍历打印。。。  写这么多重复代码并不是良好的设计模式

下面我们引进迭代器模式,自己定义iterator也可以,这里直接用java自带的java.util.Iterator

public class DinerMenuIterator  implements Iterator {    MenuItem[] menuItems;    int position = 0;    @Override    public boolean hasNext() {        if(position >= menuItems.length || menuItems[position] == null) {            return false;        }        else {            return true;        }    }    @Override    public Object next() {        MenuItem menuItem = menuItems[position];        position = position + 1;        return menuItem;    }}
public class DinerMenu {    static final int MAX_ITEMS = 6;    int numberOfItems = 0;    MenuItem[] menuItems;    public DinerMenu() {        menuItems = new MenuItem[MAX_ITEMS];        addItem("aaa", "description", true, 2.99);        addItem("bbb", "description", true, 2.99);        addItem("ccc", "description", true, 2.99);    }    public void addItem(String name, String description, boolean vegetarian, double price) {        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);        if(numberOfItems > MAX_ITEMS) {            System.out.println("menu已经满了,不能再添加了");        }        else {            menuItems[numberOfItems] = menuItem;            numberOfItems = numberOfItems + 1;        }    }    public Iterator createIterator() {        return new DinerMenuIterator(menuItems);    }    //删除掉这个方法,它会暴露出内部具体实现//    public MenuItem[] getMenuItems() {//        return menuItems;//    }}另一个菜单PancakeHouseMenu也是同理定义(不给出了)

服务员类基于iterator的改造:

public class Waitress {    Menu pancakeHouseMenu;    Menu dinerMenu;    public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) { //面向接口编程,解除与某个具体类的强耦和        this.pancakeHouseMenu = pancakeHouseMenu;        this.dinerMenu = dinerMenu;    }    public void printMenu() {        Iterator pancakeIterator = pancakeHouseMenu.createIterator();        Iterator dinerIterator = dinerMenu.createIterator();        System.out.println("Menu");        printMenu(pancakeIterator);        printMenu(dinerIterator);    }    public void printMenu(Iterator iterator) {        while(iterator.hasNext()) {            MenuItem menuItem = (MenuItem) iterator.next();            System.out.println(menuItem.getName());            System.out.println(menuItem.getDescription());            System.out.println(menuItem.getPrice());        }    }}

好,可以说应用迭代器模式我们很好的解决了俩种菜单实现原理不一样的问题,并将他们很好的糅合在一起。

但是考虑一下如何再菜单中再添加一个小菜单呢?比如我们想在菜单中添加一个甜品的小菜单模块,目前我们这种实现(数组,ArrayList里面的元素都是MenuItem类型的对象)并不能满足要求,所以在这里我们再引入组合模式与迭代器模式配合。

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();    }}
public class Menu extends MenuComponent {    ArrayList menuComponents = new ArrayList();    String name;    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 (MenuComponent)menuComponents.get(i);    }    public String getName() {        return name;    }    public String getDescription() {        return description;    }    public void print() {        System.out.println(getName());        System.out.println(getDescription());        System.out.println("--------------------");        Iterator iterator = menuComponents.iterator();        while (iterator.hasNext()) {            MenuComponent menuComponent = (MenuComponent) iterator.next();            menuComponent.print();        }    }}
public class Waitress {    MenuComponent allMenus;    public Waitress(MenuComponent allMenus) {        this.allMenus = allMenus;    }    public void printMenu() {        allMenus.print();           //调用对应顶层    }}
public class MenuTestDrive {    public static void main(String[] args) {        MenuComponent pancakeHouseMenu = new Menu("pancake", "breakfast");        MenuComponent dinerMenu = new Menu("diner", "lunch");        MenuComponent dessertMenu = new Menu("dissert", "dissert");        MenuComponent allMenus = new Menu("All MENU", "所有菜单都放一起");        allMenus.add(pancakeHouseMenu);        allMenus.add(dinerMenu);        dessertMenu.add(new MenuItem("蛋挞", "小甜品", true, 3.89));  //在甜品菜单添加一个小甜品        dinerMenu.add(dessertMenu);                                   // 在晚餐菜单添加甜品菜单        Waitress waitress = new Waitress(allMenus);        waitress.printMenu();    }}

原来数组或ArrayList中都是MenuItem对象不能满足新增字菜单,而我们现在是进一步封装了一层,MenuItem和Menu都是MenuComponent,所以这个时候代码扩展性变得更好。

0 0
原创粉丝点击