设计模式——组合模式

组合模式的一般定义:将对象组合成树形结构,表示整体!对于使用者来说,单个对象和整体是一致的。

组合模式一般在树形结构(层次结构)中应用较多,例如:菜单结构,文件夹结构;一般情况下是整体与单个对象具有很大的相似性;

使用组合模式实现菜单管理:

首先定义菜单的抽象类:

/*
 * 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;
    }
}
AbstractMenu

定义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

定义叶子节点,与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;
    }
}
LeafMenu

测试代码:

/*
 * 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();
    }
}
CompositeModelTest

输出结果:

开始测试... ...
根节点
- 一级节点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

原文地址:https://www.cnblogs.com/tengpan-cn/p/6402062.html