Java设计模式-组合模式

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战java

继Java设计模式-外观模式后的组合模式它也来了哦,让咱们一块儿来瞧一瞧吧!!!😁 会了就当复习丫,不会来一块儿来看看吧。web

很喜欢一句话:“八小时内谋生活,八小时外谋发展”。编程

若是你也喜欢,让咱们一块儿坚持吧!!设计模式

共勉😁安全

初入夏时markdown

1、前言

1)引入:

在现实生活中,存在不少“部分-总体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣服与衣柜、以及厨房中的锅碗瓢盆等。ide

在这里插入图片描述

在软件开发中也是如此,如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,若是用组合模式来实现会很方便。post

2)概述:

组合模式(Composite Pattern):将对象组合成树形结构以表示“部分总体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具备一致性。。学习

有时候又叫作部分-总体模式,它使咱们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序能够像处理简单元素同样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦测试

3)角色:

1.抽象根节点Component 是组合中的对象声明接口,在适当的状况下,实现全部类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。

2.树枝节点Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操做,如增长(add)和删除(remove)等。

3.叶子节点Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。

4)使用场景:

1.你想表示对象的部分-总体层次结构

2.你但愿用户忽略组合对象与单个对象的不一样,用户将统一地使用组合结构中的全部对象。

组合模式正是应树形结构而生,因此组合模式的使用场景就大都是是出现树形结构的地方。

好比:文件目录显示,多级目录呈现等树形结构数据的操做。

2、代码实现

案例:

以下图,咱们在访问别的一些管理系统时,常常能够看到相似的菜单。一个菜单能够包含菜单项(菜单项是指再也不包含其余内容的菜单条目),也能够包含带有其余菜单项的菜单,所以使用组合模式描述菜单就很恰当,咱们的需求是针对一个菜单,打印出其包含的全部菜单以及菜单项的名称。

在这里插入图片描述

要实现该案例,咱们先画出类图:

在这里插入图片描述

代码:

不论是菜单仍是菜单项,都应该继承自统一的接口,这里姑且将这个统一的接口称为菜单组件。

//菜单组件 不论是菜单仍是菜单项,都应该继承该类
public abstract class MenuComponent {

    protected String name;
    protected int level;

    //添加菜单
    public void add(MenuComponent menuComponent){
        System.out.println("文件不能添加菜单");
        throw new UnsupportedOperationException();
    }

    //移除菜单
    public void remove(MenuComponent menuComponent){
        System.out.println("文件不能移除菜单");
        throw new UnsupportedOperationException();
    }

    //获取指定的子菜单
    public MenuComponent getChild(int i){
        System.out.println("文件没有子菜单");
        throw new UnsupportedOperationException();
    }

    //获取菜单名称
    public String getName(){
        return name;
    }

    public void print(){
        throw new UnsupportedOperationException();
    }
}
复制代码

这里的MenuComponent定义为抽象类,由于有一些共有的属性和行为要在该类中实现,Menu和MenuItem类就能够只覆盖本身感兴趣的方法,而不用搭理不须要或者不感兴趣的方法。

举例来讲,Menu类能够包含子菜单,所以须要覆盖add()、remove()、getChild()方法,可是MenuItem就不该该有这些方法。

我这里就是打印句话,而后抛出异常。

Menu

Menu类已经实现了除了getName方法的其余全部方法,由于Menu类具备添加菜单,移除菜单和获取子菜单的功能。

public class Menu extends MenuComponent {

    private List<MenuComponent> menuComponentList;

    public Menu(String name,int level){
        this.level = level;
        this.name = name;
        menuComponentList = new ArrayList<MenuComponent>();
    }

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

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

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

    @Override
    public void print() {

        for (int i = 1; i < level; i++) {
            System.out.print("--");
        }
        System.out.println(name);
        for (MenuComponent menuComponent : menuComponentList) {
            menuComponent.print();
        }
    }
}
复制代码

MenuItem

MenuItem是菜单项,不能再有子菜单,因此添加菜单,移除菜单和获取子菜单的功能并不能实现。

public class MenuItem extends MenuComponent {

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

    @Override
    public void print() {
        for (int i = 1; i < level; i++) {
            System.out.print("--");
        }
        System.out.println(name);
    }
}
复制代码

测试

public class Client {

    public static void main(String[] args) {
        MenuComponent component = new Menu("crush",2);
        MenuComponent c2 = new Menu("wyh1",1);
        MenuComponent wyh4 = new MenuItem("wyh4", 2);
        MenuComponent wyh5 = new MenuItem("wyh5", 2);

        component.add(c2);

        component.add(wyh4);
        //wyh4.add(wyh5);

        component.print();	
        /** * 输出: * --crush * wyh1 * --wyh4 */
    }
}
复制代码

上面这个代码案例,是属于组合模式中的透明模式,你没看错,组合模式有两种。我忘记写在前面啦,这里再来给你们介绍一下哈:

  • 透明组合模式

    透明组合模式中,抽象根节点角色中声明了全部用于管理成员对象的方法,好比在示例中 MenuComponent 声明了 addremovegetChild 方法,这样作的好处是确保全部的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。

    透明组合模式的缺点是不够安全,由于叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,所以为其提供 add()、remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段若是调用这些方法可能会出错(若是没有提供相应的错误处理代码)

  • 安全组合模式

    在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点 Menu 类中声明并实现这些方法。安全组合模式的缺点是不够透明,由于叶子构件和容器构件具备不一样的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,所以客户端不能彻底针对抽象编程,必须有区别地对待叶子构件和容器构件。

在这里插入图片描述

3、总结

优势

  • 组合模式 屏蔽了对象系统的层次差别性(树节点和叶子节点为不一样类型),将客户代码与复杂的容器对象解耦,使得客户端能够忽略层次间的差别,简化了客户端代码,使用一致的行为控制不一样层次。高层模块调用简单。
  • 在 组合模式能够很方便地增长 树枝节点叶子节点 对象,并对现有类库无侵入,符合开闭原则

缺点

  • 若是类系统(树形结构)过于庞大,虽然对不一样层次都提供一致性操做,但客户端仍需花费时间理清类之间的层次关系;
  • 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
  • 不容易用继承的方法来增长构件的新功能;

4、自言自语

你卷我卷,你们卷,何时这条路才是个头啊。😇(仍是直接上天吧)

有时候也想停下来歇一歇,一直作一个事情,感受挺难坚持的。😁

你好,若是你正巧看到这篇文章,而且以为对你有益的话,就给个赞吧,让我感觉一下分享的喜悦吧,蟹蟹。🤗

如如有写的有误的地方,也请你们不啬赐教!!

一样如如有存在疑惑的地方,请留言或私信,定会在第一时间回复你。

持续更新中

相关文章
相关标签/搜索