HeadFirst设计模式学习之组合模式

HeadFirst设计模式学习之组合模式

组合模式定义

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

从定义出发可以得出两个结论

  • 组合模式是基于树这种数据结构的
  • 组合模式的目的是“用一致的方式处理个别对象以及对象组合”

需求

设计菜单,菜单能包含菜单项或者子菜单,子菜单能包含菜单项或者二级子菜单,以此类推。

分析

  • 菜单和菜单项应拥有共同的基类
  • 基类应该拥有菜单和菜单项的所有方法(如果不这样,我们将无法“用一致的方式处理个别对象以及对象组合”)
  • 迭代器才是正确的遍历方法。

设计基类MenuComponent

abstract class MenuComponent {
public void add(MenuComponent mc)
{
    throw  new UnsupportedOperationException();
}
public void remove(MenuComponent mc)
{
    throw new UnsupportedOperationException();
}
public String getDescription()
{
    throw new UnsupportedOperationException();
}
public void print()
{
    throw new UnsupportedOperationException();
}

}

在分析中提到,基类应该拥有菜单和菜单项的所有方法,但是这样会造成的问题是,菜单项会具有其本不该有的方法,如add(),所以在基类里做了抛出异常的实现,这样,菜单和菜单项只需要复写需要的方法,用户调用不适当的方法会抛出异常

菜单类Menu

class Menu extends MenuComponent {
    private String description;
    private ArrayList<MenuComponent> al;
    public Menu(String desc) {
        // TODO Auto-generated constructor stub
        this.description=desc;
        al=new ArrayList<MenuComponent>();

    }
    @Override
    public void add(MenuComponent mc) {
        // TODO Auto-generated method stub
        al.add(mc);
    }
    @Override
    public void remove(MenuComponent mc) {
        // TODO Auto-generated method stub
        al.remove(mc);
    }
    @Override
    public String getDescription() {
        // TODO Auto-generated method stub
        return description;
    }
    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println(getDescription());
        MyIterator MI=createIterator();
        while(MI.hasNext())
        {
            MenuComponent mc=(MenuComponent)MI.next();
            mc.print();
        }
    }

    public MyIterator createIterator()
    {
        return new arrayDataIterator(al);
    }

}

在这个菜单类里,我们复写了所有的方法并且添加了用于实现迭代器的方法createIterator(),这里的
arrayDataIterator类是在我的上一篇博客——迭代器模式中实现的用于遍历ArrayList的简单迭代器。
在方法print()中,是用迭代器实现的对菜单项的遍历和递归,这也解释了为什么要用迭代器:如果不用,递归会变得十分复杂(并非所有的菜单都一定会用ArrayList来存储菜单项)。

菜单项MenuItem

class MenuItem extends MenuComponent {
private String description;
public MenuItem(String desc) {
    // TODO Auto-generated constructor stub
    this.description=desc;
}
@Override
public String getDescription() {
    // TODO Auto-generated method stub
    return description;
}
@Override
public void print() {
    // TODO Auto-generated method stub
    System.out.println(getDescription());
}


}

在这里,我们只需要实现两个方法:用于得到描述的getDescription()和打印信息的print()。

测试

先放上测试代码:

public static void main(String[] args)
{
    Menu menu = new Menu("菜单");
    Menu elseMenu = new Menu("其他");
    MenuItem item1 = new MenuItem("设置");
    MenuItem item2 = new MenuItem("其他选项1");
    MenuItem item3 = new MenuItem("其他选项2");
    menu.add(elseMenu);
    menu.add(item1);
    elseMenu.add(item3);
    elseMenu.add(item2);
    menu.print();

}

上述代码,菜单包含菜单项设置和子菜单其他,其他子菜单包含两个菜单项:其他选项1和其他选项2,最后打印菜单信息。

测试结果

菜单
其他
其他选项2
其他选项1
设置

组合模式是为了用一致的方式处理个别对象以及对象组合,但是仅仅用组合模式并不如想象般美好——存储对象的数据结构可能不止一种,这就带来了复杂的递归操作(最糟糕的是每增加一种,都需要对递归进行相应的改变),但是迭代器可以将这个致命的缺点完美解决了,迭代器使组合的递归变得简单并且——也是最重要的——增加数据结构,只需要增加迭代器而不用修改代码!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值