组合模式

定义

  • 将对象组合成树形结构以表示 “部分-整体” 的层次结构
  • Composite 使得用户对单个对象和组合对象的使用具有一致性(稳定)

image-20211014145422732

image-20211014145446600

其实根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用,而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义)让它们具备一致行为,将对象组合成树形结构以表示 “部分-整体” 的层次结构。在组合模式中,整个树形结构中的对象都属于同一种类型,带来的好处就是用户不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给用户的使用带来极大的便利。

使用场景

  • 希望客户端可以忽略组合对象与单个对象的差异时
  • 处理一个树形结构时

角色

抽象构件(Component)角色

它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为

树枝构件(Composite)角色

  • 是组合中的分支节点对象,它有子节点。它实现了抽象构件角色中声明的接口,它的主要作用是存储和管理子部件
  • 通常包含 Add()、Remove()、GetChild() 等方法

树叶构件(Leaf)角色

是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中声明的公共接口

代码实现

image-20210806105240445

MenuComponent.java

/**
 * 抽象根节点
 *
 * @author BNTang
 * @date 2021/10/12
 */
@Data
public abstract class MenuComponent {
    protected String name;
    protected int level;

    /**
     * 添加子菜单
     * 可以添加菜单,可以添加菜单项,声明为父类型
     *
     * @param menuComponent 菜单组件
     */
    public void add(MenuComponent menuComponent) {
        // 如果是菜单项,下面不能再有子菜单, 菜单项不覆盖此方法
        // 如果调用的话, 就会报不支持此操作
        throw new UnsupportedOperationException();
    }

    /**
     * 移除子菜单   和添加菜单同理
     *
     * @param menuComponent 菜单组件
     */
    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    /**
     * 获取指定菜单
     *
     * @param index 索引
     * @return {@link MenuComponent}
     */
    public MenuComponent getChild(int index) {
        throw new UnsupportedOperationException();
    }

    /**
     * 打印菜单名称(包含子菜单和子菜单项)
     * 对于菜单和菜单项 他们的实现方法是不一样.
     * 定义一个抽象方法,让子类去实现
     */
    public abstract void print();
}

Menu.java

/**
 * 菜单类  树枝节点
 *
 * @author BNTang
 * @date 2021/10/12
 */
public class Menu extends MenuComponent {
    /**
     * 菜单可以有多个子菜单或者子菜单间项
     */
    private final List<MenuComponent> menuComponentList = new ArrayList<>();

    Menu(String name, int level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void add(MenuComponent menuComponent) {
        menuComponentList.add(menuComponent);
    }

    @Override
    public void remove(MenuComponent menuComponent) {
        menuComponentList.remove(menuComponent);
    }

    @Override
    public MenuComponent getChild(int index) {
        return menuComponentList.get(index);
    }

    @Override
    public void print() {
        IntStream.range(0, level).forEach(i -> System.out.print("--"));

        // 打印菜单名称
        System.out.println(name);
        menuComponentList.forEach(MenuComponent::print);
    }
}

MenuItem.java

/**
 * 菜单项,属于叶子节点
 *
 * @author BNTang
 * @date 2021/10/12
 */
public class MenuItem extends MenuComponent {
    public MenuItem(String name, int level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void print() {
        IntStream.range(0, level).forEach(i -> System.out.print("--"));
        System.out.println(name);
    }
}

Client.java

/**
 * 客户端
 *
 * @author BNTang
 * @date 2021/10/12
 */
public class Client {
    public static void main(String[] args) {
        MenuComponent menu1 = new Menu("菜单管理", 2);
        menu1.add(new MenuItem("添加菜单", 3));
        menu1.add(new MenuItem("编辑菜单", 3));

        MenuComponent menu2 = new Menu("权限管理", 2);
        menu2.add(new MenuItem("删除权限", 3));
        menu2.add(new MenuItem("更新权限", 3));

        MenuComponent menu3 = new Menu("角色管理", 2);
        menu3.add(new MenuItem("更新角色", 3));
        menu3.add(new MenuItem("添加角色", 3));

        MenuComponent rootMenu = new Menu("系统管理", 1);

        rootMenu.add(menu1);
        rootMenu.add(menu2);
        rootMenu.add(menu3);
        rootMenu.print();
    }
}

UML 图

image-20210807100919944

image-20210807101141084

优点

  • 清楚地定义分层次的复杂对象,表示对象的全部或部分层次
  • 让客户端忽略了层次的差异,方便对整个层次结构进行控制
  • 简化客户端代码

源码应用

JDK:Container

image-20210807102728344

image-20210807102821849

image-20210807102927624

image-20210807120646998

如上是 java.awt 做图形化界面的这个类。

myBatis:SqlNode

image-20210807101854028

image-20210807101908052

image-20210807101934818

image-20210807102026189

image-20210807102113048

image-20210807102413165

image-20211014145932289

posted @ 2021-08-06 10:56  BNTang  阅读(48)  评论(0编辑  收藏  举报