(超详细,超易懂)设计模式(九):组合模式,孙悟空过桥的故事

如果你也喜欢C#开发或者.NET开发,可以关注我,我会一直更新相关内容,并且会是超级详细的教程,只要你有耐心,基本上不会有什么问题,如果有不懂的,也可以私信我加我联系方式,我将毫无保留的将我的经验和技术分享给你,不为其他,只为有更多的人进度代码的世界,而进入代码的世界,最快捷和最容易的就是C#.NET,准备好了,就随我加入代码的世界吧!
一、简介

        组合模式是一种结构型设计模式,它允许将对象组合成树状结构,并以统一的方式对待树中的所有对象。组合模式使得客户端可以一致地使用单个对象或组合对象,无需关心对象的具体类型。

        在组合模式中,有两种基本角色:组合对象和叶子对象。组合对象可以包含其他组合对象或叶子对象,并且可以以相同的方式对待它们。叶子对象是不能再包含任何其他对象的最小单元。

        组合模式的核心思想是通过递归组合对象,形成树状结构。这样可以方便地对整个树进行操作,无论是对整个树还是其中的某个节点,都可以使用统一的方式进行处理。

二、为什么要学习组合模式

        2.1 简化代码结构

        组合模式通过将对象组织成树形结构,可以简化复杂的代码结构。通过使用组合模式,可以将一系列的对象组织成一个树状结构,从而使得代码更加清晰、易于理解和维护。

        2.2 提高代码的灵活性

        组合模式封装了对象之间的关系,使得客户端可以一视同仁地处理单个对象和对象的组合。这样,在不改变客户端代码的情况下,可以通过扩展组合的方式来增加新的功能。

        2.3 增强代码的复用性

        组合模式将对象组织成树形结构,可以通过复用相同的组合方式来创建不同的树形结构。这样,可以减少代码的重复编写,提高代码的复用性。

        2.4 实现层次化结构

        组合模式可以实现层次化的结构,使得对象之间的依赖关系更加清晰。通过使用组合模式,可以将对象分成不同的层次,每个层次都有自己的职责和行为。

三、组合模式在项目中有哪些实际应用

        3.1 文件系统

        文件系统是一个常见的应用组合模式的场景。文件系统可以由文件和文件夹组成,文件夹可以包含其他文件夹和文件。文件和文件夹是可以递归组合的。

        3.2 UI组件库

        UI组件库通常采用组合模式来管理和呈现各种UI组件。UI组件库通常由一个根组件开始,然后可以包含其他子组件。这些子组件可以进一步包含其他子组件,以此类推。

        3.3 组织结构

        组织结构可以使用组合模式来表示。一个组织可以由部门组成,部门可以包含其他部门和员工。这种组合结构可以方便地表示组织中的层级关系。

        3.4 菜单和子菜单

        在一个应用程序中,菜单和子菜单可以使用组合模式来管理。菜单可以包含其他子菜单和菜单项。这种组合结构可以方便地表示菜单的层级关系。

        3.5 图形操作

        图形操作可以使用组合模式来管理图形对象之间的关系。可以将图形对象组合成更大的图形对象,以方便进行操作和管理。

四、组合模式在代码中的实现与讲解

        4.1 背景

        孙悟空需要和沙悟净一起过一座桥,这座桥连接两座山峰。孙悟空代表抽象部分,沙悟净代表实现部分,桥则是连接两者的接口。

        4.2 实现 

// 抽象部分 - 孙悟空
public abstract class SunWuKong
{
    protected IAbility ability; // 持有实现部分的接口

    public void SetAbility(IAbility ability)
    {
        this.ability = ability;
    }

    public abstract void CrossBridge(); // 跨越桥梁的方法
}

// 实现部分接口 - 能力
public interface IAbility
{
    void ImplementAbility();
}

// 具体实现部分 - 千里眼和顺风耳
public class QianLiYan : IAbility
{
    public void ImplementAbility()
    {
        Console.WriteLine("使用千里眼,穿越桥梁");
    }
}

public class ShunFengEr : IAbility
{
    public void ImplementAbility()
    {
        Console.WriteLine("使用顺风耳,穿越桥梁");
    }
}

// 具体实现部分 - 水性
public class ShuiXing : IAbility
{
    public void ImplementAbility()
    {
        Console.WriteLine("擅长水性,游泳穿越桥梁");
    }
}

// 具体实现部分 - 无能力
public class WuNengLi : IAbility
{
    public void ImplementAbility()
    {
        Console.WriteLine("没有能力,但可以通过桥梁");
    }
}

// 具体抽象部分 - 孙悟空
public class ConcreteSunWuKong : SunWuKong
{
    public override void CrossBridge()
    {
        Console.Write("孙悟空:");
        ability.ImplementAbility();
    }
}

// 客户端代码
class Program
{
    static void Main(string[] args)
    {
        SunWuKong sunWuKong = new ConcreteSunWuKong();
        IAbility ability;

        // 孙悟空使用千里眼和顺风耳穿越桥梁
        ability = new QianLiYan();
        sunWuKong.SetAbility(ability);
        sunWuKong.CrossBridge();

        ability = new ShunFengEr();
        sunWuKong.SetAbility(ability);
        sunWuKong.CrossBridge();

        Console.WriteLine();

        // 孙悟空和沙悟净使用水性穿越桥梁
        ability = new ShuiXing();
        sunWuKong.SetAbility(ability);
        sunWuKong.CrossBridge();

        ability = new ShuiXing();
        SunWuKong shaWuJing = new ConcreteSunWuKong();
        shaWuJing.SetAbility(ability);
        shaWuJing.CrossBridge();

        Console.WriteLine();

        // 孙悟空和沙悟净没有能力但也可以通过桥梁
        ability = new WuNengLi();
        sunWuKong.SetAbility(ability);
        sunWuKong.CrossBridge();

        ability = new WuNengLi();
        shaWuJing.SetAbility(ability);
        shaWuJing.CrossBridge();
    }
}

运行代码后,将输出以下结果:

孙悟空:使用千里眼,穿越桥梁
孙悟空:使用顺风耳,穿越桥梁

孙悟空:擅长水性,游泳穿越桥梁
孙悟空:擅长水性,游泳穿越桥梁

孙悟空:没有能力,但可以通过桥梁
孙悟空:没有能力,但可以通过桥梁

        4.3 讲解

  1. 首先,定义了一个抽象部分 SunWuKong。该类中包含一个实现部分接口 IAbility 的属性 ability,以及一个抽象的跨越桥梁的方法 CrossBridge()

  2. 接着,定义了实现部分接口 IAbility,其中包含一个具体实现能力的方法 ImplementAbility()

  3. 然后,实现了两种具体的实现部分:千里眼和顺风耳(QianLiYan)以及水性(ShuiXing),它们都实现了 IAbility 接口,并实现了自己的具体能力。

  4. 还实现了一个无能力的具体实现部分 WuNengLi,同样实现了 IAbility 接口,但是 ImplementAbility() 方法没有具体的实现,仅作为一个示例。

  5. 接着,实现了一个具体抽象部分 ConcreteSunWuKong,继承自 SunWuKong。在 CrossBridge() 方法中,通过调用 ability.ImplementAbility() 来实现具体的能力。

  6. 在客户端代码中,创建了一个 ConcreteSunWuKong 对象,并通过调用 SetAbility() 方法设置不同的能力。然后,通过调用 CrossBridge() 方法来展示不同能力的穿越桥梁的方式。

  7. 最后,运行代码,可以看到不同的能力被桥接到 SunWuKong 对象上,而不需要修改 SunWuKong 类的代码。这样,我们可以在不改变孙悟空对象的情况下,灵活地添加、修改或扩展能力。

五、组合模式需要注意的地方

        5.1 适用性

        组合模式适用于需要表示对象的层次结构,并希望对单个对象和组合对象进行一致处理的情况。如果系统中没有这种层次结构或者不需要对单个对象和组合对象进行一致处理,那么使用组合模式可能会带来不必要的复杂性。

        5.2 客户端代码

        在使用组合模式时,客户端代码需要通过调用组合对象的方法来访问对象的层次结构。这可能会增加客户端代码的复杂性,因为客户端需要处理不同类型的对象(单个对象和组合对象)。因此,需要仔细设计和组织客户端代码,以保持其简洁和可读性。

        5.3 添加和删除子对象

        组合模式允许动态地添加和删除子对象,这可能会导致一些复杂性。在添加和删除子对象时,需要考虑对象的一致性和正确性。例如,当删除一个组合对象时,需要确保其子对象也被删除,以避免内存泄漏。

        5.4 叶节点和组合节点的区分

        在组合模式中,叶节点表示单个对象,而组合节点表示组合对象。需要清楚地区分这两种类型的节点,并在设计和实现中加以体现。这样可以使代码更加可读和可维护。

        5.5 对象的一致性

        组合模式要求单个对象和组合对象具有一致的接口和行为。这意味着在设计和实现时需要保持对象之间的一致性,以避免在使用组合模式时出现意想不到的问题。

  • 36
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值