• 组合模式


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

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

     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格式
    帮助, 一些辅助项
    关于我们, 软件制作方的一些消息
    帮助中心, 电话和邮箱咨询

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

  • 相关阅读:
    【记录】【MySQL】填充字符串函数 LPAD(str,len,padstr)
    nvm安装node和npm,个人踩坑记录
    win10系统下cmd输入一下安装的软件命令提示拒绝访问解决办法
    bootstrap大图轮播手机端不能手指滑动解决办法
    JS中函数声明与函数表达式的异同
    javaScript实现归并排序
    js插入节点appendChild和insertBefore
    JS的事件冒泡和事件捕获
    js 停止事件冒泡 阻止浏览器的默认行为
    事件绑定的几种常见方式
  • 原文地址:https://www.cnblogs.com/NaLanZiYi-LinEr/p/11667774.html
Copyright © 2020-2023  润新知