组合模式

来源:互联网 发布:python做服务器 编辑:程序博客网 时间:2024/05/18 05:31

组合模式

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

这个模式能够创建一个树形结构,在同一个结构中处理嵌套菜单和菜单项组。通过将菜单和项放在相同的结构中,我们创建了一个“整体/部分”层次结构,即由菜单和菜单项组成的对象树,但是可以将它视为一个整体,像是一个大菜单。

这是一个树形结构

graph LRnote-->leat1note-->leat2note-->leat3

带子元素的元素成为节点(node)

没有子元素的元素成为叶节点(leat)

==组合模式让我们能用树形结构创建对象的结构,树里面包含了组合以及个别的对象。==

==使用组合结构,我们能他相同的操作应用在组合和个别的对象上,换句话说,子啊大多数情况下,我们可以++忽略++对象组合和个别对象之间的差别。==

利用组合设计菜单

需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项。

实现菜单组件

菜单组件的角色为叶节点和组合节点提供一个共同的接口。

==所以的组件都必须实现MenuComponent接口,然而,叶节点和组合节点的角色不同,所以有些方法可能并不适合某些节点,面对这种情况,有时候,你最好是抛出运行时异常。==

/** * @author lzlj21@163.com *  对每个方法都提供默认的实现 *  因为有些方法只对菜单项有意义,而有些方法只对菜单有有意, *  默认实现时抛出UnsupportedOperationException *  异常,这样,如果菜单项或菜单不支持某个操作,他们就不需要做任何事情,直接继承默认实现就可以了。 */public abstract class MenuComponent {    /**     *      * @param component     *      * 新增菜单     *      */    public void add(MenuComponent component){        throw new UnsupportedOperationException();    }    /**     * @param component     *      * 删除菜单     */    public void remove(MenuComponent component){        throw new UnsupportedOperationException();    }    /**     * @param i     *      * 取得菜单组件     */    public void getChild(int i){        throw new UnsupportedOperationException();    }    /**     *  菜单项操作     *      *      */    public String getName(){        throw new UnsupportedOperationException();    }    public String getDescripion(){        throw new UnsupportedOperationException();    }    public boolean isVegetarian(){        throw new UnsupportedOperationException();    }    /**     * 打印     */    public void print(){        throw new UnsupportedOperationException();    }}

实现菜单项

/** * @author lzlj21@163.com *  *  菜单项 * */public class MenuItem extends MenuComponent {    String  name;    String description;    String vegetarian;    double price;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getDescription() {        return description;    }    public void setDescription(String description) {        this.description = description;    }    public String getVegetarian() {        return vegetarian;    }    public void setVegetarian(String vegetarian) {        this.vegetarian = vegetarian;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }    /* (实现菜单打印)     * @see com.tkn.fdemo.menu.MenuComponent#print()     *      */    @Override    public void print() {        System.out.println(" "+getName());        if (isVegetarian()) {            System.out.println("{v}");        }        System.out.println(", "+getPrice());        System.out.println("  --- "+getDescripion());    }}

实现组合菜单

/** * @author lzlj21@163.com * 菜单 * */public class Menu extends MenuComponent {    ArrayList memuComponents=new ArrayList<>();    String name;    String description;    public Menu(String name, String description) {        this.name = name;        this.description = description;    }    @Override    public void add(MenuComponent component) {        memuComponents.add(component);    }    @Override    public void remove(MenuComponent component) {        memuComponents.remove(component);    }    @Override    public MenuComponent getChild(int i) {        return (MenuComponent) memuComponents.get(i);    }    /* (non-Javadoc)     * @see com.tkn.fdemo.menu.MenuComponent#print()     * 用迭代器遍历所以菜单     */    @Override    public void print() {        System.out.println(getName());        System.out.println(", "+getDescripion());        System.out.println("------------------");        Iterator iterator = memuComponents.iterator();        while(iterator.hasNext()){            MenuComponent menuComponent = (MenuComponent)iterator.next();            menuComponent.print();        }    }}

女招待(测试准备)

public class Waitress {    MenuComponent allMenu;    public Waitress(MenuComponent allMenu) {        super();        this.allMenu = allMenu;    }    public void printMenu(){        allMenu.print();    }}

测试

public class MenuTestDrive {    public static void main(String[] args) {        /**         * 定义菜单         */        MenuComponent pancakHouseMenu=new Menu("pancake", "breakfase");        MenuComponent pancakHouseMenu1=new Menu("pancake1", "breakfase1");        MenuComponent pancakHouseMenu2=new Menu("pancake2", "breakfase2");        MenuComponent pancakHouseMenu3=new Menu("pancake3", "breakfase3");        MenuComponent pancakHouseMenu4=new Menu("pancake4", "breakfase4");        MenuComponent allMenus=new Menu("all menus", "all menus cobined");        /**         * 全部菜单添加到根菜单         */        allMenus.add(pancakHouseMenu);        allMenus.add(pancakHouseMenu1);        allMenus.add(pancakHouseMenu2);        allMenus.add(pancakHouseMenu3);        allMenus.add(pancakHouseMenu4);        MenuComponent menuItem=new MenuItem("apple","apaple pie",true,11.2);        // 添加菜单项        pancakHouseMenu4.add(menuItem);        // 添加全部菜单        Waitress waitress=new Waitress(allMenus);        // 打印菜单        waitress.printMenu();    }}

组合模式为什么违反了单一责任

==组合模式以单一责任设计原则换取透明性==

通过让组件的接口同时包含一些管理子节点和叶节点的操作,客户就可以将组合和叶节点一视同仁。也就是说,一个元素究竟是组合还是叶节点,对客户是透明的。


组合迭代器

public abstract class MenuComponent {    //其他部分代码    //添加组合调用的方法    abstract createIterator();}

public class MenuItem extends MenuComponent {    //其他部分代码    public Iterator createIterator{        return new NullIteartor();    }}

public class Menu extends MenuComponent {    //其他部分代码    public Iterator createIterator{        return new ComPositeIteator(menuComponents.iterator());    }}

/** * @author lzlj21@163.com *  组合迭代器 *  实现了util.Iterator接口 */public class CompositeIterator implements Iterator {    //堆栈数据    Stack stack =new Stack<>();    /**     * @param iterator     * 将要遍历的顶层组合的迭代器传入,抛进堆栈数据结构中     *      */    public CompositeIterator(Iterator iterator) {        stack.push(iterator);    }    @Override    public boolean hasNext() {        /**         * 判断堆栈中是否还有数据         */        if (stack.empty()) {            return false;        }else{            /**             * 从堆栈的顶层取出迭代器,看看是否还有下一个元素,如果他没有元素,             * 我们将它弹出 ,然后递归的调用hasNext()             * 否则我们将返回true             */            Iterator iterator=(Iterator) stack.peek();            if (!iterator.hasNext()) {                stack.pop();                return hasNext();            }else{                return true;            }        }    }    @Override    public Object next() {        // 判断是否还有下一个数据        if (hasNext()) {            /**             * 如果还有下一个,取出目前的迭代器,然后取出他的下一个元素             */            Iterator iterator=(Iterator) stack.peek();            MenuComponent component = (MenuComponent)iterator.next();            /**             * 如果是一个菜单元素,就有了另一个需要被包含进遍历中的组合,             * 所以需要把它丢进堆栈中,             * 不管是不是菜单我们都返回组件             */            if (component instanceof Menu) {                stack.push(component.createIterator());            }            return component;        }else {            return null;        }    }}
原创粉丝点击