组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。
组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,
从而使得客户程序与复杂元素的内部结构解耦。
何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。
2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。
关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作数也可以是操作数、操作符和另一个操作数。
2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。
优点: 1、高层模块调用简单。 2、节点自由增加。
缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。
注意事项:定义时为具体类。
组合模式中涉及到三个角色:
抽象构件(Component)角色:这是一个抽象角色,上面实现中Graphics充当这个角色,
它给参加组合的对象定义出了公共的接口及默认行为,可以用来管理所有的子对象(在透明式的组合模式是这样的)。
在安全式的组合模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝结构对象给出。
树叶构件(Leaf)角色:树叶对象时没有下级子对象的对象,上面实现中Line和Circle充当这个角色,定义出参加组合的原始对象的行为
树枝构件(Composite)角色:代表参加组合的有下级子对象的对象,
上面实现中ComplexGraphics充当这个角色,树枝对象给出所有管理子对象的方法实现,如Add、Remove等。
该实例基于WPF实现,直接上代码,下面为三层架构的代码。
一 Model
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Shapes;
namespace 设计模式练习.Model.组合模式
{
//画一个圆
internal class Circle : Graphics
{
List<Graphics> graphics = new List<Graphics>();
public Circle(string name) : base(name)
{
}
//开始绘制
public override void Draw()
{
//绘制图形
foreach (var line in graphics)
{
line.Draw();
this.Description += $"{line.Name}";
}
}
public void Add(Graphics line)
{
graphics.Add(line);
}
public void Remove(Graphics line)
{
graphics.Remove(line);
}
}
}
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.组合模式
{
//图形抽象类
public abstract class Graphics
{
public string Name { get; set; }
public string Description { get; set; }
protected Graphics(string name)
{
Name = name;
}
//画图方法
public abstract void Draw();
}
}
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.组合模式
{
public class Line : Graphics
{
//存储多个图形
private List<Graphics> points = new List<Graphics>();
//复杂图形类
public Line(string name) : base(name)
{
}
//画图: 由多个点组成的线段
public override void Draw()
{
foreach (Graphics point in points)
{
point.Draw();
this.Description += $"画{point.Name},";
}
}
public void Add(Graphics point)
{
points.Add(point);
}
public void Remove(Graphics point)
{
points.Remove(point);
}
}
}
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.组合模式
{
//简单图形:点
public class Point : Graphics
{
public Point(string name) : base(name)
{
}
//重写父类抽象方法
public override void Draw()
{
this.Description = $"画{Name}";
}
}
}
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Animation;
namespace 设计模式练习.Model.组合模式
{
//绘制复杂图形
public class Rectangle : Graphics
{
//记录加入的线段
List<Graphics> lines = new List<Graphics>();
public Rectangle(string name) : base(name)
{
}
//开始绘制
public override void Draw()
{
//绘制图形
foreach (var line in lines)
{
line.Draw();
this.Description += $"{line.Name}";
}
}
public void Add(Graphics line)
{
lines.Add(line);
}
public void Remove(Graphics line)
{
lines.Remove(line);
}
}
}
二 View
XML
<Window x:Class="设计模式练习.View.组合模式.Combination"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:设计模式练习.View.组合模式"
mc:Ignorable="d"
Title="Combination" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding Res1}"/>
<Label Grid.Row="1" Grid.Column="0" Content="{Binding Res2}"/>
<Label Grid.Row="2" Grid.Column="0" Content="{Binding Res3}"/>
<Label Grid.Row="3" Grid.Column="0" Content="{Binding Res4}"/>
<Button Grid.Row="0" Grid.Column="2" Content="画点" Command="{Binding add1Command}"/>
<Button Grid.Row="1" Grid.Column="2" Content="画线" Command="{Binding add2Command}"/>
<Button Grid.Row="2" Grid.Column="2" Content="画矩形" Command="{Binding add3Command}"/>
<Button Grid.Row="3" Grid.Column="2" Content="画圆" Command="{Binding Add4Command}"/>
<Label Grid.Row="0" Grid.Column="1" Visibility="{Binding A1}">
<Label.Content>
<TextBlock Text="." FontSize="100" VerticalAlignment="Center"/>
</Label.Content>
</Label>
<Label Grid.Row="1" Grid.Column="1" Visibility="{Binding A2}" >
<Label.Content>
<Line X1="10" Y1="20" X2="260" Y2="20" Stroke="Red" StrokeThickness="10"/>
</Label.Content>
</Label>
<Rectangle Grid.Row="2" Grid.Column="1" Fill="Red" Width="100" Height="100" StrokeThickness="3" Visibility="{Binding A3}"/>
<Ellipse Grid.Row="3" Grid.Column="1" Width="100" Height="100" Fill="Blue" Visibility="{Binding A4}"/>
</Grid>
</Window>
三 ViewModel
cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 设计模式练习.Model.组合模式;
namespace 设计模式练习.ViewModel.组合模式
{
partial class Combination_ViewModel : ObservableObject
{
[ObservableProperty]
private string res1;
[ObservableProperty]
private string res2;
[ObservableProperty]
private string res3;
[ObservableProperty]
private string res4;
[ObservableProperty]
private string a1;
[ObservableProperty]
private string a2;
[ObservableProperty]
private string a3;
[ObservableProperty]
private string a4;
public Combination_ViewModel()
{
A1 = "Collapsed";
A2 = "Collapsed";
A3 = "Collapsed";
A4 = "Collapsed";
}
//画点
[RelayCommand]
private void add1()
{
Graphics point = new Point("点1");
point.Draw();
Res1 = point.Description;
A1 = "Visible";
}
//画线
[RelayCommand]
private void add2()
{
Graphics point = new Point("点1");
Graphics point2 = new Point("点2");
Graphics point3 = new Point("点3");
Line line = new Line("线");
line.Add(point);
line.Add(point2);
line.Add(point3);
line.Draw();
Res2 = line.Description;
A2 = "Visible";
}
//画矩形
[RelayCommand]
private void add3()
{
Line line = new Line("线");
Line line2 = new Line("线2");
Line line3 = new Line("线3");
Rectangle rectangle = new Rectangle("矩形");
rectangle.Add(line);
rectangle.Add(line2);
rectangle.Add(line3);
rectangle.Draw();
Res3 = rectangle.Description;
A3 = "Visible";
}
//画圆
[RelayCommand]
private void Add4()
{
Rectangle rectangle = new Rectangle("矩形");
Rectangle rectangle2 = new Rectangle("矩形2");
Circle circle = new Circle("圆");
circle.Add(rectangle);
circle.Add(rectangle2);
circle.Draw();
Res4 = circle.Description;
A4 = "Visible";
}
}
}