设计模式:Composite--组合模式-树形结构

组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便,看看关系图:

透明方式:

在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。

安全方式:

在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。其结构图如图 2 所示。

 

使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。

代码实现:文件夹和文件例子,根节点加入文件和文件夹,文件夹里面再加文件等,然后递归显示名字

/**
 * 节点抽象
 */
public interface IFile {
    //获取显示文件夹或文件的父类
    public void display();

    //添加子节点
    public boolean add(IFile iFile);

    //移除
    public boolean remove(IFile iFile);

    public List<IFile> getChild();
}

*********************************************************************

/**
 * 文件夹
 */
public class Folde implements IFile {

    private String name;
    private List<IFile>  childrens;

    public Folde(String name) {
        this.name = name;
        childrens = new ArrayList<>();
    }

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public boolean add(IFile iFile) {
        return childrens.add(iFile);
    }

    @Override
    public boolean remove(IFile iFile) {
        return childrens.remove(iFile);
    }

    @Override
    public List<IFile> getChild() {
        return childrens;
    }
}

*********************************************************************
package com.atguigu.composite;

import java.util.List;

/**
 * 文件
 */

public class File  implements IFile {
    private String name;

    public File(String name) {
        this.name = name;
    }

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public boolean add(IFile iFile) {
        return false;
    }

    @Override
    public boolean remove(IFile iFile) {
        return false;
    }

    @Override
    public List<IFile> getChild() {
        return null;
    }
}



*********************************************************************
package com.atguigu.composite;


import org.springframework.util.CollectionUtils;

import java.util.List;

public class MailClass {
    public static void main(String[] args) {
        //c盘
        Folde root = new Folde("C");
        //beifeng目录
        Folde beifengFolde = new Folde("beifeng");
        //beifeng.txt文件
        File file = new File("beifeng.txt");

        root.add(beifengFolde);
        root.add(file);

        Folde ibeifengFolde = new Folde("ibeifeng");
        beifengFolde.add(ibeifengFolde);
        File ifile = new File("ibeifeng.txt");
        ibeifengFolde.add(ifile);
        displayTree(root,0);
    }


    public static void displayTree(IFile iFile,int deep){
        for(int i = 0; i < deep; i++) {
            System.out.print("--");
        }

        //显示自己的名称
        iFile.display();
        //获取子树
        List<IFile> child = iFile.getChild();
        if(!CollectionUtils.isEmpty(child)) {
            for(int i = 0; i < child.size(); i++) {
                IFile ifile = child.get(i);
                if(ifile instanceof File) {
                    for(int j = 0; i < deep; i++) {
                        System.out.print("--");
                    }
                    ifile.display();
                }else {
                    displayTree(ifile,deep+1);
                }
            }
        }

    }
}

 测试结果:

二、事例

case1

/**
 * @auhtor
 * @create 2023-01-11-11:18
 * 安全方式
 */
public abstract class Component {
    protected String name;

    public Component(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Component setName(String name) {
        this.name = name;
        return this;
    }
    public abstract void display();
}

// 非叶子节点
public class Composite extends Component {

    private List<Component> child = new ArrayList<>();

    public Composite(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println(getName());
        if (child != null && child.size() > 0) {
            for (Component component : child) {
                component.display();
            }
        }
    }

    public boolean addChild(Component component) {
        child.add(component);
        return true;
    }

    public boolean removeChild(Component component) {
        child.remove(component);
        return true;
    }

    public Component getChild(int index) {
        return child.get(index);
    }

}

// 叶子节点
public class Leaf extends Component{
    public Leaf(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println(getName());
    }

}

输出

public static void main(String[] args) {
        // component 抽象类定义基本方法,非叶子节点composite定义各特有方法, leaf叶子节点定义自己方法
        Composite driveD = new Composite("D盘");

        Composite doc = new Composite("文档");
        doc.addChild(new Leaf("简历.doc"));
        doc.addChild(new Leaf("项目介绍.ppt"));

        driveD.addChild(doc);

        Composite misic = new Composite("音乐");
        Composite jay = new Composite("周杰伦");
        jay.addChild(new Leaf("双截棍.mp3"));
        jay.addChild(new Leaf("告白气球.mp3"));

        Composite jack = new Composite("张学友");
        jack.addChild(new Leaf("吻别.mp3"));
        jack.addChild(new Leaf("一千个伤心的理由..mp3"));

        misic.addChild(jay);
        misic.addChild(jack);

        driveD.addChild(misic);

        driveD.display();

    }

// console
D盘
文档
简历.doc
项目介绍.ppt
音乐
周杰伦
双截棍.mp3
告白气球.mp3
张学友
吻别.mp3
一千个伤心的理由..mp3

case2

/**
 * @auhtor
 * @create 2023-01-11-9:50
 *
 *  透明方式
 */
public abstract class Node {
    protected String name;

    public Node(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public Node setName(String name) {
        this.name = name;
        return this;
    }

    public void add(Node node) throws Exception {
        throw new RuntimeException("不可添加");
    }

    public abstract void display();
}

// 非叶子节点
public class Folder extends Node{

    private List<Node> child = new ArrayList<>();

    public Folder(String name) {
        super(name);
    }

    @Override
    public void add(Node node) throws Exception {
        child.add(node);
    }

    @Override
    public void display() {
        System.out.println(this.name);
        if (child != null && child.size() > 0) {
            for (Node node : child) {
                node.display();
            }
        }
    }
}

// 叶子节点
public class Leaf extends Node {

    public Leaf(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println(this.name);
    }
}

输出

public class MainClient {

    public static void main(String[] args) {
        // 组合模式 leaf 叶子节点  composite 非叶子节点
        Node node = new Folder("F:\\yubin\\sql_script\\20220408\\contractmg");
        try {
            createTree(node);
        } catch (Exception e) {
            e.printStackTrace();
        }
        node.display();
    }


    public static void createTree(Node node) throws Exception {
        File file = new File(node.getName());
        // 找出这个目录下面所有的文件和文件夹
        File[] files = file.listFiles();
        for (File file1 : files) {
            if (file1.isFile()) {
                Leaf leaf = new Leaf(file1.getAbsolutePath());
                node.add(leaf);
            }
            if (file1.isDirectory()) {
                Folder folder = new Folder(file1.getAbsolutePath());
                node.add(folder);
                createTree(folder);
            }
            
        }
    }
}

// console
F:\yubin\sql_script\20220408\contractmg
F:\yubin\sql_script\20220408\contractmg\20220414合同脚本.rar
F:\yubin\sql_script\20220408\contractmg\准生产
F:\yubin\sql_script\20220408\contractmg\准生产\contract.sql
F:\yubin\sql_script\20220408\contractmg\准生产\dic-service.sql
F:\yubin\sql_script\20220408\contractmg\生产
F:\yubin\sql_script\20220408\contractmg\生产\contract.sql
F:\yubin\sql_script\20220408\contractmg\生产\dic-service.sql

case3

// 抽象层,接口或者抽象类
public abstract class OrganizationComponent {

    protected String name;

    protected String desc;

    public String getDesc() {
        return desc;
    }

    public OrganizationComponent setDesc(String desc) {
        this.desc = desc;
        return this;
    }

    public OrganizationComponent(String name, String desc) {

        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public OrganizationComponent setName(String name) {
        this.name = name;
        return this;
    }

    public void add(OrganizationComponent o) throws Exception{
        throw new RuntimeException("无法添加");
    }

    public void remove(OrganizationComponent o) throws Exception{
        throw new RuntimeException("无法删除");
    }

    public abstract void display(int deep);
}

// 非叶子节点 大学
public class University extends OrganizationComponent {
    private List<OrganizationComponent> child = new ArrayList<>();

    public University(String name, String desc) {
        super(name, desc);
    }

    @Override
    public void add(OrganizationComponent o) throws Exception {
        child.add(o);
    }

    @Override
    public void remove(OrganizationComponent o) throws Exception {
        child.remove(o);
    }

    @Override
    public void display(int deep) {
        String str = "";
        for (int i = 0; i < deep; i++) {
            str += "-";
        }
        System.out.println(str + getName() + ":" + getDesc());
        if (child != null && child.size() > 0) {
            for (OrganizationComponent component : child) {
                component.display(deep + 4);
            }
        }

    }
}


// 非叶子节点,学院
public class College extends OrganizationComponent {
    private List<OrganizationComponent> child = new ArrayList<>();

    public College(String name, String desc) {
        super(name, desc);
    }

    @Override
    public void add(OrganizationComponent o) throws Exception {
        child.add(o);
    }

    @Override
    public void remove(OrganizationComponent o) throws Exception {
        child.remove(o);
    }

    @Override
    public void display(int deep) {
        String str = "";
        for (int i = 0; i < deep; i++) {
            str += "-";
        }
        System.out.println(str + getName() + ":" + getDesc());
        if (child != null && child.size() > 0) {
            for (OrganizationComponent component : child) {
                component.display(deep + 4);
            }
        }
    }
}

// 叶子节点,专业
public class Department extends OrganizationComponent {

    public Department(String name, String desc) {
        super(name, desc);
    }

    @Override
    public void display(int deep) {
        String str = "";
        for (int i = 0; i < deep; i++) {
            str += "-";
        }
        System.out.println(str + getName() + ":" + getDesc());
    }
}

输出

public class MainClient {
    public static void main(String[] args) throws Exception{
        University university = new University("清华大学","国内顶级大学");
        College college = new College("计算机学院","计算机学院");
        Department department = new Department("软件工程","软件工程不错");
        Department department2 = new Department("网络工程","网络工程");
        Department department3 = new Department("计算机科学与技术","计算机科学与技术是老牌专业");
        college.add(department);
        college.add(department2);
        college.add(department3);

        College college2 = new College("通信工程","通信工程不错");
        Department department4 = new Department("信息工程","信息工程哈可以");
        Department department5 = new Department("通信工程","通信工程值得学习");
        college2.add(department4);
        college2.add(department5);

        university.add(college);
        university.add(college2);

        university.display(0);
    }
}

// console
清华大学:国内顶级大学
----计算机学院:计算机学院
--------软件工程:软件工程不错
--------网络工程:网络工程
--------计算机科学与技术:计算机科学与技术是老牌专业
----通信工程:通信工程不错
--------信息工程:信息工程哈可以
--------通信工程:通信工程值得学习

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值