组合模式

  • 定义:
    将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
  • UML:


    image.png
  • 模型:
    餐厅点餐软件上的,菜单->子菜单->菜单项,菜单下可能有子菜单或者菜单项,子菜单下也可能有子菜单或菜单项,类似树形结构


    image.png
//抽象出统一的菜单组件(这个是统一对外暴露的数据结构)
public abstract class MenuComponent {
    public String getName() {
        return "";
    }
    public String getDescription() {
        return "";
    }
    public float getPrice() {
        return 0;
    }
    public boolean isVegetable() {
        return false;
    }
    public abstract void print();
    public Iterator getIterator() {
        return new NullIterator();
    }
}
//具体的一个菜单项
public class MenuItem extends MenuComponent{
    private String name,description;
    private boolean vegetable;
    private float price;
    public MenuItem(String name,String description,boolean vegetable,float price){
        this.name=name;
        this.description=description;
        this.vegetable=vegetable;
        this.price=price;
    }
    @Override
    public String getName(){
        return name;
    }
    @Override
    public String getDescription(){
        return description;
    }
    @Override
    public float getPrice(){
        return price;
    }
    @Override
    public boolean  isVegetable(){
        return vegetable;
    }
    @Override
    public void print() {
        System.out.println(getName() + "***" + getPrice() + "***"
                + getDescription());
    }
}
//菜单
public class DinerMenu extends MenuComponent {
    private final static int Max_Items = 5;
    private int numberOfItems = 0;
        //数组方式记录子菜单项
    private MenuComponent[] menuItems;
    public DinerMenu() {
        menuItems = new MenuComponent[Max_Items];
        addItem("vegetable Blt", "bacon&lettuce&tomato&cabbage", true, 3.58f);
        addItem("Blt", "bacon&lettuce&tomato", false, 3.00f);
        addItem("bean soup", "bean&potato salad", true, 3.28f);
        addItem("hotdog", "onions&cheese&bread", false, 3.05f);
        addSubMenu(new SubMenu());
    }
    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems++;
        }
    }
       //子菜单再添加子菜单(子菜单特有的方法)
    private void addSubMenu(MenuComponent mMenuComponent){
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = mMenuComponent;
            numberOfItems++;
        }
    }
        //这里返回的是一个包装迭代器,
    public Iterator getIterator() {
        return new ComposeIterator(new DinerIterator());
    }
        //自己的迭代器
    class DinerIterator implements Iterator {
        private int position;
        public DinerIterator() {
            position = 0;
        }
        @Override
        public boolean hasNext() {
            if (position < numberOfItems) {
                return true;
            }
            return false;
        }
        @Override
        public Object next() {
            MenuComponent menuItem = menuItems[position];
            position++;
            return menuItem;
        }
        @Override
        public void remove() {}
    }
    @Override
    public void print() {
        System.out.println("****This is DinerMenu****");
    };
}
//装饰迭代器(操作时先调用被装饰者方法)
public class ComposeIterator implements Iterator {
    private Stack stack = new Stack();
    public ComposeIterator(Iterator iterator) {
        stack.push(iterator);
    }
    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        if (stack.empty()) {
            return false;
        }
        Iterator iterator = stack.peek();
        if (!iterator.hasNext()) {
            stack.pop();
            return hasNext();
        } else {
            return true;
        }
    }
    @Override
    public Object next() {
        if (hasNext()) {
            Iterator iterator = stack.peek();
            MenuComponent mMenuComponent = (MenuComponent) iterator.next();
            stack.push(mMenuComponent.getIterator());
            return mMenuComponent;
        }
        return null;
    }
    @Override
    public void remove() {}
}

//子菜单
public class SubMenu extends MenuComponent {
    private ArrayList menuItems;
    public SubMenu() {
        menuItems = new ArrayList();
        addItem("Apple Cookie", "Apple&candy&Cookie", true, 1.99f);
        addItem("Banana Cookie", "Banana&candy&Cookie", false, 1.59f);
        addItem("Orange Cookie", "Orange&Cookie", true, 1.29f);
    }
    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }
    public Iterator getIterator() {
        return new ComposeIterator(menuItems.iterator());
    }
    @Override
    public void print() {
        System.out.println("****This is SubMenu****");
    };
    // 其他功能代码
}
//缺省适配
public class NullIterator implements Iterator{
    @Override
    public boolean hasNext() {
        return false;
    }
    @Override
    public Object next() {
        return null;
    }
    @Override
    public void remove() {}
}
//没有子菜单的菜单
public class CakeHouseMenu extends MenuComponent {
      //集合形式存储菜单项
    private ArrayList menuItems;
    public CakeHouseMenu() {
        menuItems = new ArrayList();
        addItem("KFC Cake Breakfast", "boiled eggs&toast&cabbage", true, 3.99f);
        addItem("MDL Cake Breakfast", "fried eggs&toast", false, 3.59f);
        addItem("Stawberry Cake", "fresh stawberry", true, 3.29f);
        addItem("Regular Cake Breakfast", "toast&sausage", true, 2.59f);
    }
    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }
    public Iterator getIterator() {
        return new ComposeIterator(menuItems.iterator());
    }
    @Override
    public void print() {
        System.out.println("****This is CakeHouseMenu****");
    };
    // 其他功能代码
}
  • 使用组合模式:
public class Waitress {
    private ArrayList iterators = new ArrayList();
    public Waitress() {}
    public void addComponent(MenuComponent mMenuComponent) {
        iterators.add(mMenuComponent);
    }
    public void printMenu() {
        Iterator iterator;
        MenuComponent menuItem;
                //遍历时并不关心菜单或子菜单项的数据结构,只要调用其暴露出来的接口Iterator。
        for (int i = 0, len = iterators.size(); i < len; i++) {
            iterators.get(i).print();
            iterator = iterators.get(i).getIterator();
            while (iterator.hasNext()) {
                menuItem = (MenuComponent) iterator.next();
                menuItem.print();
            }
        }
    }
}
  • 测试:
public class MainTest {
    public static void main(String[] args) {
        Waitress mWaitress = new Waitress();
        CakeHouseMenu mCakeHouseMenu = new CakeHouseMenu();
        DinerMenu mDinerMenu = new DinerMenu();
        mWaitress.addComponent(mCakeHouseMenu);
        mWaitress.addComponent(mDinerMenu);
        mWaitress.printMenu();
    }
}
  • 通过使用组合模式,我们将菜单与子菜单抽象成菜单组件。对使用者来说是透明的,操作具有一致性,忽略整体与部分的差异。
    子菜单可以看成存储菜单组件的容器,这样我们就可以组合出很多层次,形成复杂的树形结构。

你可能感兴趣的:(组合模式)