Design Patterns(九):Composite Pattern--VB代码
★★★★☆
将对象组合成结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
结构图

角色
l 抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。在安全式的合成模式里,构件角色并不是定义出管理子对象的方法,这一定义由树枝构件对象给出。
l 树叶构件(Leaf)角色:树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。
l 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝对象给出所有的管理子对象的方法。
动机
客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将客户代码的频繁变化,带来了代码的维护性差、扩展性差等弊端。
如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
意图
将对象组合成结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
示意性代码
透明方式
在Component里面声明所有用来管理子类对象的方法,包括add()、remove(),以及getChild()方法。这样做的好处是所有的构件类都有相同的接口。客户程序可以一致对待树叶类对象与合成类对象。不必关心所使用对象的内部构造。

透明方式
Imports System
Imports System.Collections

'MainApp test application

Public Class MainAppClass MainApp

Public Shared Sub Main()Sub Main()
'Create a tree structure
Dim root As New Composite("root")
root.Add(New Leaf("Leaf A"))
root.Add(New Leaf("Leaf B"))

Dim com As New Composite("Composite X")
com.Add(New Leaf("Leaf XA"))
com.Add(New Leaf("Leaf XB"))
root.Add(com)

'Add and remove a leaf
Dim leaf As New Leaf("LeafD")
root.Add(leaf)
root.Remove(leaf)

'Recursively display tree
root.Display(1)

'Wait for user
Console.ReadLine()
End Sub
End Class

'"Component"

Public MustInherit Class ComponentClass Component
Protected name As String
' Constructor

Public Sub New()Sub New(ByVal name As String)
Me.name = name
End Sub

Public MustOverride Sub Add()Sub Add(ByVal c As Component)

Public MustOverride Sub Remove()Sub Remove(ByVal c As Component)

Public MustOverride Sub Display()Sub Display(ByVal depth As Integer)
End Class

'"Composite"

Public Class CompositeClass Composite
Inherits Component
Private children As New ArrayList

Public Sub New()Sub New(ByVal name As String)
MyBase.new(name)
End Sub

Public Overrides Sub Add()Sub Add(ByVal c As Component)
children.Add(c)
End Sub

Public Overrides Sub Remove()Sub Remove(ByVal c As Component)
children.Remove(c)
End Sub
'Recursively display child nodes

Public Overrides Sub Display()Sub Display(ByVal depth As Integer)
For Each c As Component In children
c.Display(depth + 2)
Next
End Sub
End Class

'"Leaf"

Public Class LeafClass Leaf
Inherits Component
' Constructors

Public Sub New()Sub New(ByVal name As String)
MyBase.new(name)
End Sub

Public Overrides Sub Add()Sub Add(ByVal c As Component)
Console.WriteLine("Cannot add to a leaf")
End Sub

Public Overrides Sub Remove()Sub Remove(ByVal c As Component)
Console.WriteLine("Cannot remove from a leaf")
End Sub

Public Overrides Sub Display()Sub Display(ByVal depth As Integer)
Console.WriteLine(New String("-"c, depth) + name)
End Sub
End Class
安全方式
在Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的做法,因为树叶类型的对象根本就没有管理子类对象的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。这个选择的缺点是不够透明,因为树叶类和合成类将具有不同的接口。

安全方式
Imports System
Imports System.Collections

'MainApp test application

Public Class MainAppClass MainApp

Public Shared Sub Main()Sub Main()
'Create a tree structure
Dim root As New Composite("root")
root.Add(New Leaf("Leaf A"))
root.Add(New Leaf("Leaf B"))

Dim com As New Composite("Composite X")
com.Add(New Leaf("Leaf XA"))
com.Add(New Leaf("Leaf XB"))
root.Add(com)

'Add and remove a leaf
Dim leaf As New Leaf("LeafD")
root.Add(leaf)
root.Remove(leaf)

'Recursively display tree
root.Display(1)

'Wait for user
Console.ReadLine()
End Sub
End Class

'"Component"

Public MustInherit Class ComponentClass Component
Protected name As String
' Constructor

Public Sub New()Sub New(ByVal name As String)
Me.name = name
End Sub

Public MustOverride Sub Display()Sub Display(ByVal depth As Integer)
End Class

'"Composite"

Public Class CompositeClass Composite
Inherits Component
Private children As New ArrayList

Public Sub New()Sub New(ByVal name As String)
MyBase.new(name)
End Sub

Public Sub Add()Sub Add(ByVal c As Component)
children.Add(c)
End Sub

Public Sub Remove()Sub Remove(ByVal c As Component)
children.Remove(c)
End Sub
'Recursively display child nodes

Public Overrides Sub Display()Sub Display(ByVal depth As Integer)
For Each c As Component In children
c.Display(depth + 2)
Next
End Sub
End Class

'"Leaf"

Public Class LeafClass Leaf
Inherits Component
' Constructors

Public Sub New()Sub New(ByVal name As String)
MyBase.new(name)
End Sub

Public Overrides Sub Display()Sub Display(ByVal depth As Integer)
Console.WriteLine(New String("-"c, depth) + name)
End Sub
End Class
实例
该例子演示了依次向场景(root)中添加简单图形(RedLine,Blue Circle,Green Box)和复杂图形(Two Cricle)。最后同显示简单图形一样显示场景。

实例程序
Imports system
Imports system.collections



Public Class MainAppClass MainApp

Public Shared Sub Main()Sub Main()

'Create a tree structure
Dim root As New CompositeElement("Picture")
root.Add(new PrimitiveElement("Red Line")
root.Add(new PrimitiveElement("Blue Circle")
root.Add(new PrimitiveElement("Green Box")

Dim comp As New CompositeElement("Two Cricle")
comp.Add(New PrimitiveElement("Black Circle"))
comp.Add(New PrimitiveElement("White Circle"))
root.Add(comp)

'Add and remove a PrimitiveElement
Dim pe As New PrimitiveElement("Yellow Line")
root.Add(pe)
root.Remove(pe)

'Recursivelly display nodes
root.Display(1)

'Wait for user
Console.Read()

End Sub
End Class

'"Component" Treenode

Public MustInherit Class DrawingElementClass DrawingElement
Protected name As String

'Constructor

Public Sub New()Sub New(ByVal name As String)
Me.name = name
End Sub


Public MustOverride Sub Add()Sub Add(ByVal d As DrawingElement)

Public MustOverride Sub Remove()Sub Remove(ByVal d As DrawingElement)

Public MustOverride Sub Display()Sub Display(ByVal indent As Integer)
End Class

'"Leaf"

Public Class PrimitiveElementClass PrimitiveElement
Inherits DrawingElement

'Constructor

Public Sub New()Sub New(ByVal name As String)
MyBase.new(name)
End Sub


Public Overrides Sub Add()Sub Add(ByVal c As DrawingElement)
Console.WriteLine("Cannt add to a PrimitiveElement")
End Sub


Public Overrides Sub Remove()Sub Remove(ByVal c As DrawingElement)
Console.WriteLine("Cannot remove from a PrimitiveElement")
End Sub


Public Overrides Sub Display()Sub Display(ByVal indent As Integer)
Console.WriteLine(New String("-"c, indent) & " " & name)
End Sub
End Class

'"Composite"

Public Class CompositeElementClass CompositeElement
Inherits DrawingElement
Private elements As New ArrayList

'Constructor

Public Sub New()Sub New(ByVal name As String)
MyBase.new(name)
End Sub


Public Overrides Sub Add()Sub Add(ByVal d As DrawingElement)
elements.Add(d)
End Sub


Public Overrides Sub Remove()Sub Remove(ByVal d As DrawingElement)
elements.Remove(d)
End Sub


Public Overrides Sub Display()Sub Display(ByVal indent As Integer)

Console.WriteLine(New String("-"c, indent) & "+ " & name)

' Display each child element on this node
For Each c As DrawingElement In elements
c.Display(indent + 2)
Next

End Sub
End Class
Composite模式的几个要点:
1、Composite模式采用结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
2、将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口--而非对象容器的内部实现结构--发生依赖关系,从而更能“应对变化”。
3、Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在 “表示对象容器的 Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结 构,这又是必须付出的代价。ASP.NET控件的实现在这方面为我们提供了一个很好的示范不。
4、Composite模式在具体实现中,可以让父对象中的子对象反向追溯,如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
我的理解
当客户同时要使用结构相似的简单对象和复杂对象时(复杂对象包含简单对象),Composite把复杂对象简单化,使客户程序可以像使用简单对象一样使用复杂对象。

l 抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。在安全式的合成模式里,构件角色并不是定义出管理子对象的方法,这一定义由树枝构件对象给出。
l 树叶构件(Leaf)角色:树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。
l 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝对象给出所有的管理子对象的方法。
动机
客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将客户代码的频繁变化,带来了代码的维护性差、扩展性差等弊端。
如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
意图
将对象组合成结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
示意性代码
透明方式
在Component里面声明所有用来管理子类对象的方法,包括add()、remove(),以及getChild()方法。这样做的好处是所有的构件类都有相同的接口。客户程序可以一致对待树叶类对象与合成类对象。不必关心所使用对象的内部构造。



































































































安全方式
在Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的做法,因为树叶类型的对象根本就没有管理子类对象的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。这个选择的缺点是不够透明,因为树叶类和合成类将具有不同的接口。























































































实例
该例子演示了依次向场景(root)中添加简单图形(RedLine,Blue Circle,Green Box)和复杂图形(Two Cricle)。最后同显示简单图形一样显示场景。





















































































































Composite模式的几个要点:
1、Composite模式采用结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
2、将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口--而非对象容器的内部实现结构--发生依赖关系,从而更能“应对变化”。
3、Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在 “表示对象容器的 Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结 构,这又是必须付出的代价。ASP.NET控件的实现在这方面为我们提供了一个很好的示范不。
4、Composite模式在具体实现中,可以让父对象中的子对象反向追溯,如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
我的理解
当客户同时要使用结构相似的简单对象和复杂对象时(复杂对象包含简单对象),Composite把复杂对象简单化,使客户程序可以像使用简单对象一样使用复杂对象。
参考资料
《C#设计模式(11)-Composite Pattern》 吕震宇老师
《C#面向对象设计模式纵横谈系列课程(9)》 李建中老师
分类:
Design Pattern
随笔分类 (333)
Cnblogs's
Front End
Oracle's
Software's
- Apache HTTP Server
- CodeSmith Community
- Grapecity(FAQ)
- Mybase
- ClubFarPoint(Forum)
- Beyond Compare
- CrystalReport(FAQ)
- 秀丸
- Software Advice
- Software: Business & Nonprofit | Reviews and Top Software at Capterra
- Capterra
- Business Software Reviews from Software Advice
Copyright © 2025 sekihin
Powered by .NET 9.0 on Kubernetes
Powered by .NET 9.0 on Kubernetes
![]() | 本作品采用 知识共享署名-非商业性使用 2.5 中国大陆许可协议进行许可。 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通