组合模式
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
我们通过下面的实例来演示组合模式的用法。实例演示了一个组织中员工的层次结构。
介绍
意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。
关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。
优点: 1、高层模块调用简单。 2、节点自由增加。
缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。
注意事项:定义时为具体类。
例子:
组合模式: 和树差不多
DMComposite 类里不够完善,比如取孩子和 移除孩子,添加孩子,在操作之前 都需要 做一些提前处理,空处理之类的。
Window 操作系统 里面的文件目录 就是用树(组合模式)实现的。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class dm06Composite : MonoBehaviour {
// Use this for initialization
void Start ()
{
DMComposite root = new DMComposite("Root");
DMLeaf leaf1 = new DMLeaf("GameObject");
DMLeaf leaf2 = new DMLeaf("GameObject (2)");
DMComposite gameObject1 = new DMComposite("GameObject (1)");
root.Add(leaf1);
root.Add(gameObject1);
root.Add(leaf2);
DMLeaf child1 = new DMLeaf("GameObject");
DMLeaf child2 = new DMLeaf("GameObject (1)");
gameObject1.Add(child1);
gameObject1.Add(child2);
ReadComponent(root);
}
// Update is called once per frame
void Update () {
}
//深度
private void ReadComponent(DMComponent component)
{
Debug.Log(component.Name);
List<DMComponent> childrens = component.children;
if (childrens==null||childrens.Count==0)
{
//叶子
return;
}
foreach (DMComponent child in childrens)
{
ReadComponent(child);
}
}
}
public abstract class DMComponent
{
protected string mName;
public string Name { get { return mName; } }
public DMComponent(string name)
{
mName = name;
mChildren = new List<DMComponent>();
}
public List<DMComponent> children{ get { return mChildren; }}
protected List<DMComponent> mChildren;
public abstract void Add(DMComponent Dmc);
public abstract void RemoveChild(DMComponent c);
public abstract DMComponent GetChild(int index);
}
public class DMLeaf : DMComponent
{
public DMLeaf(string name) : base(name)
{
}
public override void Add(DMComponent Dmc)
{
return;
}
public override DMComponent GetChild(int index)
{
return null;
}
public override void RemoveChild(DMComponent c)
{
return;
}
}
public class DMComposite : DMComponent
{
public DMComposite(string name) : base(name)
{
}
public override void Add(DMComponent Dmc)
{
mChildren.Add(Dmc);
}
public override DMComponent GetChild(int index)
{
return mChildren[index];
}
public override void RemoveChild(DMComponent c)
{
mChildren.Remove(c);
}
}
二叉树的链式储存,说白了就是靠引用来储存,不过因为是二叉树 因此有它的存储规律。和一些公式之类的,一般很少用,
每个子节点都有它的父节点。通过引用来表示相互间的关系,责任链模式主要也是通过引用来表示引用关系。 很类似。
namespace 二叉树链式存储
{
class BSNode
{
public BSNode LeftChild { get; set; } = null;
public BSNode RightChild { get; set; } = null;
public BSNode Parent { get; set; } = null;
public int dada { get; set; }
public BSNode() { }
public BSNode(int item)
{
this.dada = item;
}
}
class BSTree
{
private BSNode Root = null;
/// <summary>
/// 大于 根结点 放在右边 小于放在左边
/// </summary>
/// <param name="item"></param>
public void Add(int item)
{
BSNode newBSNode = new BSNode(item);
if (Root == null)
{
Root = newBSNode;
}
else
{
BSNode temp = Root;
while (true)
{ //如果 比当前 结点的数据大就放右边 小于就 放左边
if (item >= temp.dada)
{
// 如果右边为空了就插入 节点
if (temp.RightChild == null)
{
temp.RightChild = newBSNode;
newBSNode.Parent = temp;
break; //插入了数据 跳出循环
}
else
{
temp = temp.RightChild;
}
}
else //小于 放在左边
{
//往左边插入
if (temp.LeftChild == null)
{
temp.LeftChild = newBSNode;
newBSNode.Parent = temp;
break; //插入了数据 跳出循环
}
else //继续执行
{
temp = temp.LeftChild;
}
}
}
}
}
public void MiddleTraverSal() { MiddleTraverSal(Root); }
private void MiddleTraverSal(BSNode node)
{
if (node == null)
{
return;
}
MiddleTraverSal(node.LeftChild);
Console.Write(node.dada + " ");
MiddleTraverSal(node.RightChild);
}
public bool Find(int item)
{
return Find(item, Root);
}
private bool Find(int item, BSNode node)
{
if (node == null)
{
return false;
}
if (node.dada == item)
{
return true;
}
else
{
if (node.dada <= item)
{
return Find(item, node.RightChild);
}
else
{
return Find(item, node.LeftChild);
}
}
return false;
}
public bool Delete(int item)
{
BSNode temp = Root;
while (true)
{
if (temp == null) return false;
if (temp.dada == item)
{
Delete(temp);
return true;
}
if (item > temp.dada)
{
temp = temp.RightChild;
}
else
{
temp = temp.LeftChild;
}
}
}
public void Delete(BSNode node)
{
///删除的是 叶子 结点 情况1
if (node.LeftChild == null && node.RightChild == null)
{
if (node.Parent == null) //无 父 结点 就是 根结点
{
Root = null;
}
else if (node.Parent.RightChild == node) //如果结点是 父节点的 右结点
{
node.Parent.RightChild = null;
}
else if (node.Parent.LeftChild == node)
{
node.Parent.LeftChild = null;
}
return;
}
//只有右孩子 情况2
if (node.LeftChild == null && node.RightChild != null)
{
node.dada = node.RightChild.dada; //拿到数据 拿到引用
node = node.RightChild; //左 节点已经为null 直接拿到引用
return;
}
if (node.LeftChild != null && node.RightChild == null)
{
node.dada = node.LeftChild.dada;
node = node.LeftChild;
return;
}
// 情况3 左右孩子都有
BSNode Temp = node.RightChild;
while (true) //左结点最小 的
{
if (Temp.LeftChild != null) //存在左结点 一直查找到最后 右结点 中 的左子节点中寻找最小的 。
{
Temp = Temp.LeftChild;
}
else
{
break;
}
}
//BSNode Temp = node.LeftChild;
//while (true)
//{
// if (Temp.RightChild!=null)
// {
// Temp = Temp.RightChild;
// }
// else
// {
// break;
// }
//}
node.dada = Temp.dada;
Delete(Temp);
}
}
class Program
{
static void Main(string[] args)
{
BSTree bSTree = new BSTree();
int[] data = { 62, 58, 88, 47, 73, 99, 35, 51, 93, 37 };
foreach (int item in data)
{
bSTree.Add(item);
}
bSTree.Delete(88);
bSTree.MiddleTraverSal();
Console.WriteLine(bSTree.Find(99));
Console.WriteLine(bSTree.Find(990));
}
}
}
组合模式:资料 https://www.cnblogs.com/lfxiao/p/6816026.html文件 杀毒例子