组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便,看看关系图:
透明方式:
在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 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
清华大学:国内顶级大学
----计算机学院:计算机学院
--------软件工程:软件工程不错
--------网络工程:网络工程
--------计算机科学与技术:计算机科学与技术是老牌专业
----通信工程:通信工程不错
--------信息工程:信息工程哈可以
--------通信工程:通信工程值得学习