组合模式的一般定义:将对象组合成树形结构,表示整体!对于使用者来说,单个对象和整体是一致的。
组合模式一般在树形结构(层次结构)中应用较多,例如:菜单结构,文件夹结构;一般情况下是整体与单个对象具有很大的相似性;
使用组合模式实现菜单管理:
首先定义菜单的抽象类:
/* * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved */ package com.pt.composite; /** * @description 定义一个抽象的menu对象 * @author panteng * @date 17-2-15. */ public abstract class AbstractMenu { String menuName; protected Integer menuLevel; public AbstractMenu(){ } public AbstractMenu(String name){ this.menuName = name; } public abstract void clickEvent(); public abstract void add(AbstractMenu abstractMenu); public abstract void remove(AbstractMenu abstractMenu); public String getMenuName(){ return menuName; } public void setMenuName(String menuName){ this.menuName = menuName; } public Integer getMenuLevel(){ return menuLevel; } public void setMenuLevel(Integer menuLevel){ this.menuLevel = menuLevel; } }
定义Menu节点:
/* * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved */ package com.pt.composite; import java.util.ArrayList; import java.util.List; /** * @description * @author panteng * @date 17-2-15. */ public class Menu extends AbstractMenu { List<AbstractMenu> childMenus = new ArrayList<AbstractMenu>(); public Menu(){ super(); } public Menu(String name){ super(name); } @Override public void clickEvent(){ for (int i = 0; i < this.menuLevel; i++) { System.out.print("- "); } System.out.println(this.getMenuName()); for (AbstractMenu menu : childMenus) { menu.clickEvent(); } } @Override public void add(AbstractMenu abstractMenu){ abstractMenu.menuLevel = this.menuLevel + 1; childMenus.add(abstractMenu); } @Override public void remove(AbstractMenu abstractMenu){ childMenus.remove(abstractMenu); } @Override public String getMenuName(){ return super.getMenuName(); } @Override public void setMenuName(String menuName){ super.setMenuName(menuName); } }
定义叶子节点,与menu节点的区别是没有子节点,因此add和remove方法需要特殊处理
/* * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved */ package com.pt.composite; /** * @description * @author panteng * @date 17-2-15. */ public class LeafMenu extends AbstractMenu { String url; public LeafMenu(){ super(); } public LeafMenu(String name){ super(name); } public LeafMenu(String name, String url){ this.menuName = name; this.url = url; } @Override public void clickEvent(){ for (int i = 0; i < this.menuLevel; i++) { System.out.print("- "); } System.out.println("访问URL:" + url); } @Override public void add(AbstractMenu abstractMenu){ abstractMenu.menuLevel = this.menuLevel + 1; System.out.println("不支持add"); } @Override public void remove(AbstractMenu abstractMenu){ System.out.println("不支持remove"); } public String getUrl(){ return url; } public void setUrl(String url){ this.url = url; } }
测试代码:
/* * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved */ package com.pt.composite; import org.junit.Test; /** * @description * @author panteng * @date 17-2-15. */ public class CompositeModelTest { /** * */ @Test public void menuTest(){ System.out.println("开始测试... ..."); Menu rootMenu = new Menu("根节点"); rootMenu.setMenuLevel(0); Menu menu1 = new Menu("一级节点1"); Menu menu2 = new Menu("一级节点2"); Menu menu3 = new Menu("一级节点3"); rootMenu.add(menu1); rootMenu.add(menu2); rootMenu.add(menu3); Menu menu11 = new Menu("二级节点11"); Menu menu12 = new Menu("二级节点12"); menu1.add(menu11); menu1.add(menu12); Menu menu21 = new Menu("二级节点21"); Menu menu22 = new Menu("二级节点22"); menu2.add(menu21); menu2.add(menu22); Menu menu31 = new Menu("二级节点31"); Menu menu32 = new Menu("二级节点32"); menu3.add(menu31); menu3.add(menu32); LeafMenu leafMenu111 = new LeafMenu("叶子节点111", "网址1"); LeafMenu leafMenu112 = new LeafMenu("叶子节点112", "网址2"); menu11.add(leafMenu111); menu11.add(leafMenu112); LeafMenu leafMenu121 = new LeafMenu("叶子节点121", "网址3"); menu12.add(leafMenu121); LeafMenu leafMenu211 = new LeafMenu("叶子节点211", "网址4"); menu21.add(leafMenu211); LeafMenu leafMenu221 = new LeafMenu("叶子节点221", "网址5"); menu22.add(leafMenu221); LeafMenu leafMenu311 = new LeafMenu("叶子节点311", "网址6"); menu31.add(leafMenu311); rootMenu.clickEvent(); } }
输出结果:
开始测试... ... 根节点 - 一级节点1 - - 二级节点11 - - - 访问URL:网址1 - - - 访问URL:网址2 - - 二级节点12 - - - 访问URL:网址3 - 一级节点2 - - 二级节点21 - - - 访问URL:网址4 - - 二级节点22 - - - 访问URL:网址5 - 一级节点3 - - 二级节点31 - - - 访问URL:网址6 - - 二级节点32
简单总结一下,使用组合模式,对于客户端的调用很方便!局限性在于,单个对象,和组合后的对象需要有一定的相似性,可以抽象为用户调用的接口,对象多次组合只是量的增长,不会引起质的变化!
此例中只是两种类型对象的组合,实际应用中可能是多种类型对象的组合!
.NET的各种控件就应用了组合模式,这么看来
相关文章:
http://blog.csdn.net/hfmbook/article/details/7693069