组合模式

      组合模式允许用户将对象组合成树形结构来表现“整体/部分”的层次结构,从而能够以一致的方式处理单个对象以及对象组合。根据这个定义,首先能够想到的就是软件的菜单,一个菜单可以包含菜单项(菜单项是指不再包含其他内容的菜单条目),也可以包含带有其他菜单项的菜单,因此使用组合模式描述菜单就很恰当,我们的需求是针对一个菜单,打印出其包含的所有菜单以及菜单项。

      首先,不管是菜单还是菜单项,都应该继承自统一的接口,这里姑且将这个统一的接口称为菜单组件,其定义如下:

 1 public abstract class MenuComponent {
 2   public void add(MenuComponent menuComponent){
 3     throw new UnsupportedOperationException();
 4   }
 5 
 6   public void remove(MenuComponent menuComponent){
 7     throw new UnsupportedOperationException();
 8   }
 9 
10   public MenuComponent getChild(int i){
11     throw new UnsupportedOperationException();
12   }
13 
14   public String getName(){
15     throw new UnsupportedOperationException();
16   }
17 
18   public String getDescription(){
19     throw new UnsupportedOperationException();
20   }
21 
22   public void print(){
23     throw new UnsupportedOperationException();
24   }
25 }
MenuComponent

      这里选择抽象类来实现MenuComponent,是因为需要对一些方法给出默认实现,如此一来,Menu和MenuItem类就可以只覆盖自己感兴趣的方法,而不用搭理不需要或者不感兴趣的方法,举例来说,Menu类可以包含子菜单,因此需要覆盖add()、remove()、getChild()方法,但是MenuItem就不应该有这些方法。这里给出的默认实现是抛出异常,你也可以根据自己的需要改写默认实现。

      接下来定义菜单类Menu:

 1 public class Menu extends MenuComponent{
 2   private List<MenuComponent> menuComponentList;
 3   private String name;
 4   private String descrition;
 5 
 6   public Menu(String name, String description){
 7     this.name = name;
 8     this.descrition = description;
 9     menuComponentList = new ArrayList<>();
10   }
11 
12   @Override
13   public void add(MenuComponent menuComponent){
14     menuComponentList.add(menuComponent);
15   }
16 
17   @Override
18   public void remove(MenuComponent menuComponent){
19     menuComponentList.remove(menuComponent);
20   }
21 
22   @Override
23   public MenuComponent getChild(int i){
24     return menuComponentList.get(i);
25   }
26 
27   @Override
28   public String getName() {
29     return name;
30   }
31 
32   @Override
33   public String getDescription(){
34     return descrition;
35   }
36 
37   @Override
38   public void print(){
39     System.out.println(getName() + ", " + getDescription());
40     Iterator iterator = menuComponentList.iterator();
41     while(iterator.hasNext()){
42       MenuComponent menuComponent = (MenuComponent) iterator.next();
43       menuComponent.print();
44     }
45   }
46 }
Menu

      Menu类应该覆盖自己感兴趣的方法,实际上这里它覆盖了父类的所有方法,这样做的原因仅仅是因为抽象类中的所有方法都是该类需要的,假设某一天我们在MenuComponent里面增加了color()方法,该方法只针对菜单项显示灰色底色,那么Menu累就不应该覆盖color()方法了。

      让我们接着来实现MenuItem:

 1 public class MenuItem extends MenuComponent{
 2   private String name;
 3   private String descrition;
 4 
 5   public MenuItem(String name, String descrition){
 6     this.name = name;
 7     this.descrition = descrition;
 8   }
 9 
10   @Override
11   public String getName() {
12     return name;
13   }
14 
15   @Override
16   public String getDescription(){
17     return descrition;
18   }
19 
20   @Override
21   public void print(){
22     System.out.println(getName() + ", " + getDescription());
23   }
24 }
MenuItem

      MenuItem只覆盖了getName()、getDescription()、print()方法,因为其他的方法对该类并不适用。

      现在可以写个测试类看一下组合模式在菜单上面的表现了:

 1 public class MenuComponentTest {
 2   public static void main(String[] args){
 3     MenuComponentTest test = new MenuComponentTest();
 4     MenuComponent allMenu = test.createMenu();
 5     allMenu.print();
 6   }
 7 
 8   public MenuComponent createMenu(){
 9     MenuComponent fileMenu = new Menu("文件", "文件相关选项");
10     fileMenu.add(new MenuItem("设置", "可以更改一些设置项"));
11     fileMenu.add(new MenuItem("保存", "保存所有文件"));
12 
13     MenuComponent saveAsMenu = new Menu("另存为", "另存为其他一些格式");
14     saveAsMenu.add(new MenuItem("PDF", "另存为PDF格式"));
15     saveAsMenu.add(new MenuItem("docx","另存为docx格式"));
16     fileMenu.add(saveAsMenu);
17 
18     MenuComponent helpMenu = new Menu("帮助","一些辅助项");
19     helpMenu.add(new MenuItem("关于我们","软件制作方的一些消息"));
20     helpMenu.add(new MenuItem("帮助中心","电话和邮箱咨询"));
21 
22     MenuComponent allMenu = new Menu("所有菜单","包含所有菜单的菜单");
23     allMenu.add(fileMenu);
24     allMenu.add(helpMenu);
25 
26     return allMenu;
27   }
28 }

      打印结果为(没有缩进所以稍微丑了一点):

所有菜单, 包含所有菜单的菜单
文件, 文件相关选项
设置, 可以更改一些设置项
保存, 保存所有文件
另存为, 另存为其他一些格式
PDF, 另存为PDF格式
docx, 另存为docx格式
帮助, 一些辅助项
关于我们, 软件制作方的一些消息
帮助中心, 电话和邮箱咨询

      最后回顾一下这个菜单的例子,类之间的关系如下:

 

posted @ 2019-10-13 18:40  纳兰小依  阅读(344)  评论(0编辑  收藏  举报