组合模式(Composite)是针对由多个节点对象(部分)组成的树形结构的对象(整体)而发展出的一种结构型设计模式,它能够使客户端在操作整体对象或者其下的每个节点对象时做出统一的响应,保证树形结构对象使用方法的一致性,使客户端不必关注对象的整体或部分,最终达到对象复杂的层次结构与客户端解耦的目的。
组合模式的核心思想是将对象看作是一个树形结构,其中每个节点可以是一个单独的对象(叶子节点)或者一个包含其他节点的容器(组合节点)。叶子节点和组合节点都实现了相同的接口,这样客户端就可以对它们进行一致的操作,而不需要关心它们的具体类型。
组合模式有以下几个角色:
组合模式
组合模式的好处有:
组合模式的坏处有:
组合模式是一种将对象组合成树形结构的设计模式,它可以表示 「整体-部分」的层次关系,并且提供了一致的接口来操作单个对象和对象组合。应用场景有:
假设我们有一个文件系统,其中有两种类型的文件:文本文件和文件夹。文本文件是叶子节点,文件夹是组合节点,可以包含其他文件。我们想要使用组合模式来实现文件系统的层次结构,并且提供一个打印文件路径的方法。代码如下:
定义抽象组件
public
interface
File {
// 获取文件名称
String
getName
();
// 添加子文件
void
add
(File file);
// 删除子文件
void
remove
(File file);
// 获取子文件
List<File>
getChildren
();
// 打印文件路径
void
printPath
(
int space);
}
定义叶子节点
public
class
TextFile
implements
File {
private String name;
public
TextFile
(String name) {
this.name = name;
}
@Override
public String
getName
() {
return name;
}
@Override
public
void
add
(File file) {
throw
new UnsupportedOperationException(
"Text file cannot add child file");
}
@Override
public
void
remove
(File file) {
throw
new UnsupportedOperationException(
"Text file cannot remove child file");
}
@Override
public List<File>
getChildren
() {
throw
new UnsupportedOperationException(
"Text file has no child file");
}
@Override
public
void
printPath
(
int space) {
StringBuilder sp =
new StringBuilder();
for (
int i =
0; i < space; i++) {
sp.append(
" ");
}
System.out.println(sp + name);
}
}
定义组合节点
public
class
Folder
implements
File {
private String name;
private List<File> children;
public
Folder
(String name) {
this.name = name;
children =
new ArrayList<>();
}
@Override
public String
getName
() {
return name;
}
@Override
public
void
add
(File file) {
children.add(file);
}
@Override
public
void
remove
(File file) {
children.remove(file);
}
@Override
public List<File>
getChildren
() {
return children;
}
@Override
public
void
printPath
(
int space) {
StringBuilder sp =
new StringBuilder();
for (
int i =
0; i < space; i++) {
sp.append(
" ");
}
System.out.println(sp + name);
space +=
2;
for (File child : children) {
child.printPath(space);
}
}
}
客户端代码
public
class
Client {
public
static
void
main
(String[] args) {
// 创建一个根文件夹,并添加两个文本文件和一个子文件夹
File root =
new Folder(
"root");
root.add(
new TextFile(
"a.txt"));
root.add(
new TextFile(
"b.txt"));
File subFolder =
new Folder(
"subFolder");
root.add(subFolder);
// 在子文件夹中添加两个文本文件
subFolder.add(
new TextFile(
"c.txt"));
subFolder.add(
new TextFile(
"d.txt"));
// 打印根文件夹的路径
root.printPath(
0);
}
}
输出结果:
root
a.txt
b.txt
subFolder
c.txt
d.txt
package main
// importing fmt package
import (
"fmt"
)
// IComposite interface
type IComposite
interface {
perform()
}
// Leaflet struct
type Leaflet
struct {
name
string
}
// Leaflet class method perform
func
(leaf *Leaflet)
perform
() {
fmt.Println(
"Leaflet " + leaf.name)
}
// Branch struct
type Branch
struct {
leafs []Leaflet
name
string
branches []Branch
}
// Branch class method perform
func
(branch *Branch)
perform
() {
fmt.Println(
"Branch: " + branch.name)
for _, leaf :=
range branch.leafs {
leaf.perform()
}
for _, branch :=
range branch.branches {
branch.perform()
}
}
// Branch class method add leaflet
func
(branch *Branch)
add
(leaf Leaflet) {
branch.leafs =
append(branch.leafs, leaf)
}
//Branch class method addBranch branch
func
(branch *Branch)
addBranch
(newBranch Branch) {
branch.branches =
append(branch.branches, newBranch)
}
//Branch class method getLeaflets
func
(branch *Branch)
getLeaflets
() []
Leaflet {
return branch.leafs
}
// main method
func
main
() {
var branch = &Branch{name:
"branch 1"}
var leaf1 = Leaflet{name:
"leaf 1"}
var leaf2 = Leaflet{name:
"leaf 2"}
var branch2 = Branch{name:
"branch 2"}
branch.add(leaf1)
branch.add(leaf2)
branch.addBranch(branch2)
branch.perform()
}
输出结果:
G:\GoLang\examples>go run composite.go
Branch: branch 1
Leaflet leaf 1
Leaflet leaf 2
Branch: branch 2
Spring 框架也可以使用组合模式来实现对象的层次结构,它提供了一个注解叫做
@Component,它可以用来标注一个类是一个组件,即一个可被Spring管理的Bean对象。
@Component 注解有一个属性叫做value,它可以用来指定组件的名称。我们可以使用
@Component 注解来标注我们的文件类,然后在配置文件或注解中声明这些组件,Spring 就会自动创建和管理这些组件对象。
假设我们有一个文件系统,其中有两种类型的文件:文本文件和文件夹。文本文件是叶子节点,文件夹是组合节点,可以包含其他文件。我们想要使用组合模式来实现文件系统的层次结构,并且提供一个打印文件路径的方法。我们可以使用
@Component 注解来实现,代码如下:
抽象组件不用改造
public
interface
File {
// 获取文件名称
String
getName
();
// 添加子文件
void
add
(File file);
// 删除子文件
void
remove
(File file);
// 获取子文件
List<File>
getChildren
();
// 打印文件路径
void
printPath
();
}
叶子节点添加
@Component("a.txt") 注解
@Component(
"a.txt")
public
class
TextFile
implements
File {
private String name;
public
TextFile
() {
this.name =
"a.txt";
}
@Override
public String
getName
() {
return name;
}
@Override
public
void
add
(File file) {
throw
new UnsupportedOperationException(
"Text file cannot add child file");
}
@Override
public
void
remove
(File file) {
throw
new UnsupportedOperationException(
"Text file cannot remove child file");
}
@Override
public List<File>
getChildren
() {
throw
new UnsupportedOperationException(
"Text file has no child file");
}
@Override
public
void
printPath
() {
System.out.println(name);
}
}
组合节点添加
@Component("root") 注解
@Component(
"root")
public
class
Folder
implements
File {
private String name;
private List<File> children;
// 通过@Autowired注解自动注入所有类型为File的Bean对象到children集合中
@Autowired
public
Folder
(List<File> children) {
this.name =
"root";
this.children = children;
}
@Override
public String
getName
() {
return name;
}
@Override
public
void
add
(File file) {
children.add(file);
}
@Override
public
void
remove
(File file) {
children.remove(file);
}
@Override
public List<File>
getChildren
() {
return children;
}
@Override
public
void
printPath
() {
System.out.println(name);
for (File child : children) {
child.printPath();
}
}
}
SpringBoot 测试代码
@Slf4j
@SpringBootTest
class
SpringBootTest {
@Autowired
private Folder folder;
@Test
void
test
() {
folder.printPath();
}
}
输出结果:
root
a.txt
组合模式是一种常用的结构型设计模式,它可以将对象组合成树形结构,并且提供了一致的接口来操作单个对象和对象组合,是一种值得学习和掌握的设计模式。
❝关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力!
❞
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70029997/viewspace-2961097/ ,如需转载,请注明出处,否则将追究法律责任。