Android设计模式详解之组合模式

news2024/9/25 13:25:31

前言

组合模式也称为部分整体模式,结构型设计模式之一;

定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性;

使用场景:

  • 表示对象的部分-整体的层次结构时;
  • 从一个整体中能够独立出部分模块或功能的场景;

安全的组合模式

安全组合模式的UML类图:
安全组合模式的UML
Component:抽象根节点,对组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理Component的子节点。可在递归结构中定义一个接口,用于访问一个父节点,并在合适的情况下实现它。

Composite:定义有子节点的那些枝干节点的行为,存储子节点,在Component接口中实现与子节点有关的操作;

Leaf:在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为;

Client:通过Component接口操纵组合节点的对象;

模板代码

  • 定义抽象根节点,Component
abstract class Component(val name: String) {

    /**
     * 具体的逻辑交给子节点实现
     */
    abstract fun doSomething()
}
  • 定义具体枝干节点,Composite
class Composite(name: String) : Component(name) {
    //存储节点的容器
    private val components = arrayListOf<Component>()
    override fun doSomething() {
        println("枝干节点名称:$name")
        for (component in components) {
            component.doSomething()
        }
    }

    /**
     * 添加子节点
     * @param c 子节点
     */
    fun addChild(c: Component) {
        components.add(c)
    }

    /**
     * 获取子节点
     * @param index 子节点对应下标
     */
    fun getChildren(index: Int) {
        components[index]
    }

    /**
     * 移除子节点
     * @param c 子节点
     */
    fun removeChild(c: Component) {
        components.remove(c)
    }

}
  • 定义叶子节点,Leaf
class Leaf(name: String) : Component(name) {

    override fun doSomething() {
        println("叶子节点名称:$name")
    }
}
  • 编写调用测试类
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //构造一个根节点
        val root = Composite("root")
        //构造两个枝干节点
        val branch1 = Composite("branch1")
        val branch2 = Composite("branch2")
        //构造叶子节点
        val leaf1 = Leaf("leaf1")
        val leaf2 = Leaf("leaf2")
        val leaf3 = Leaf("leaf3")
        val leaf4 = Leaf("leaf4")
        //添加叶子节点
        branch1.addChild(leaf1)
        branch1.addChild(leaf2)
        branch2.addChild(leaf3)
        branch2.addChild(leaf4)
        //添加枝干节点
        root.addChild(branch1)
        root.addChild(branch2)
        root.doSomething()
    }

}

结果输出:

枝干节点名称:root
枝干节点名称:branch1
叶子节点名称:leaf1
叶子节点名称:leaf2
枝干节点名称:branch2
叶子节点名称:leaf3
叶子节点名称:leaf4

优点:结构清晰明了,逻辑容易理解;

缺点:违背依赖倒置原则,定义的抽象Component在调用时并没有起到作用,而是直接依赖的具体细节类;

我们将组合所使用到的方法addChild、removeChild、getChild定义到抽象类中,得到的是透明的组合模式

透明的组合模式

透明组合模式UML类图:
透明组合模式UML类图

模板代码

  • 定义抽象根节点,Component
abstract class Component(val name: String) {

    /**
     * 具体的逻辑交给子节点实现
     */
    abstract fun doSomething()

    /**
     * 添加子节点
     */
    abstract fun addChild(c: Component)

    /**
     * 移除子节点
     */
    abstract fun removeChild(c: Component)

    /**
     * 获取子节点
     */
    abstract fun getChildren(index: Int)
}
  • 定义具体枝干节点,Composite
class Composite(name: String) : Component(name) {
    //存储节点的容器
    private val components = arrayListOf<Component>()
    override fun doSomething() {
        println("枝干节点名称:$name")
        for (component in components) {
            component.doSomething()
        }
    }

    /**
     * 添加子节点
     * @param c 子节点
     */
    override fun addChild(c: Component) {
        components.add(c)
    }

    /**
     * 获取子节点
     * @param index 子节点对应下标
     */
    override fun getChildren(index: Int) {
        components[index]
    }

    /**
     * 移除子节点
     * @param c 子节点
     */
    override fun removeChild(c: Component) {
        components.remove(c)
    }

}
  • 定义叶子节点,Leaf
class Leaf(name: String) : Component(name) {

    override fun doSomething() {
        println("叶子节点名称:$name")
    }

    override fun addChild(c: Component) {
        throw  UnsupportedOperationException("叶子节点没有子节点")
    }

    override fun removeChild(c: Component) {
        throw  UnsupportedOperationException("叶子节点没有子节点")
    }

    override fun getChildren(index: Int) {
        throw  UnsupportedOperationException("叶子节点没有子节点")
    }
}
  • 编写测试类
object Test {

   @JvmStatic
   fun main(args: Array<String>) {
       //构造一个根节点
       val root = Composite("root") as Component
       //构造两个枝干节点
       val branch1 = Composite("branch1") as Component
       val branch2 = Composite("branch2") as Component
       //构造叶子节点
       val leaf1 = Leaf("leaf1") as Component
       val leaf2 = Leaf("leaf2") as Component
       val leaf3 = Leaf("leaf3") as Component
       val leaf4 = Leaf("leaf4") as Component
       //添加叶子节点
       branch1.addChild(leaf1)
       branch1.addChild(leaf2)
       branch2.addChild(leaf3)
       branch2.addChild(leaf4)
       //添加枝干节点
       root.addChild(branch1)
       root.addChild(branch2)
       root.doSomething()
   }

}

结果输出:

枝干节点名称:root
枝干节点名称:branch1
叶子节点名称:leaf1
叶子节点名称:leaf2
枝干节点名称:branch2
叶子节点名称:leaf3
叶子节点名称:leaf4

优点:满足依赖倒置原则,细节依赖于抽象;
缺点:叶子节点没有子节点,无法操作,覆盖的抽象方法是多余的;

Android源码中的组合模式

  • View树结构
    View树UML图

总结

优点:组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让高层模块忽略了层次的差异,方便对整个层次结构进行控制;

缺点:在新增构件时不好对枝干中的构件类型进行限制,不能依赖类型系统来施加约束,因为大多情况下,他们都来自于相同的抽象层;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/127485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

屏幕录制为什么没声音?检查这2项,轻松解决

相信很多人在录制视频的时候都会遇到各种各样的问题&#xff0c;比如录制的视频没有声音。屏幕录制为什么没声音&#xff1f;今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音&#xff0c;你可以试试这个方法。 一、检查是否打开电脑系…

amCharts 5: Maps 附加组件

amCharts 5: Maps 附加组件 将reverseGeodata设置添加到MapPolygonSeries。如果设置为true&#xff0c;将反转GeoJSON数据中多边形角的方向。 向MapLine添加了新的linechanged事件。 amCharts 5&#xff1a;地图 amCharts:Maps是amCharts:Charts的附加组件。使用它可以将完整的…

Java学习笔记【7】面向对象

⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ &#x1f300; 个人首页&#xff1a;&#x1f3e0; 星空之路Star &#x1f3e0; &#x1f300; 所属专栏&#xff1a;&#x1f4d6; Java知识点总结 &#x1f4d6; &#x1f300; 大家好&#x1f91d; 我是 &#x1f449;老孙&#x1f448; &…

操作系统期末考试必会题库5——文件管理

1、画出文件系统的层次模型&#xff0c;并描述各层的功能。 2、某文件系统为一级目录&#xff0c;文件的数据一次性写入磁盘&#xff0c;已经写入的文件不可修改&#xff0c;但可以多次创建新文件&#xff0c;请回答&#xff1a; (1) 采用哪种文件物理结构形式更适合&#xff…

hnu计网实验二-网络基础编程实验(JAVA\Python3)

前言&#xff1a;这次实验用的是python语言&#xff0c;但是本人的python也不是很强&#xff0c;所以代码大部分也是借鉴别人的。实验本身还是很有趣的 一、实验目的 通过本实验&#xff0c;学习采用Socket&#xff08;套接字&#xff09;设计简单的网络数据收发程序&#xf…

Qt编写雷达模拟仿真工具

一、前言 雷达模拟仿真工具&#xff0c;已发布很长一段时间&#xff0c;一直以来没有好好整理该系列文章&#xff0c;在刘哥6.5的极力推荐下&#xff0c;整理出该系列的更加详细细节的文章出来。懒散了很久&#xff0c;也颓废了不少&#xff0c;人啊&#xff0c;感觉不能颓废下…

Python入门小案例: 采集全网表情包图片

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 环境使用: Python 3.8 Pycharm 2021.2版本 模块使用: import requests >>> pip install requests -pip install -i https://pypi.doubanio.com/simple/ requests import re 安装pyt…

Revit中:该扶手的坡度可能与梯段及平台楼梯不平行问题

一、Revit中单独绘制楼梯扶手问题 单独绘制扶手的时候总是会出现梯段及平台上的楼梯不平行&#xff0c;这种情况怎么办? 在正常操作下楼梯会制动生成扶手&#xff0c;但有时候还是回碰到单独绘制扶手的时候然后就会出现这样的些问题&#xff0c;如图1、图2所示。 解决方法&…

(Research)深度迁移学习使循环肿瘤细胞的病变追踪成为可能

Tips: 深度迁移学习使循环肿瘤细胞的病变追踪成为可能 &#xff08;Nat Commun&#xff09;&#xff0c;原文链接: https://pubmed.ncbi.nlm.nih.gov/36509761/ 摘要&#xff1a; CTC做为液体活检中最重要的一个目标&#xff0c;如果能够对 CTC 进行溯源那么就能够实现肿瘤的早…

mediasoup create/connect WebRtcTransport 流程分析

一. 前言 在这篇博客中我们介绍了 mediasoup-demo 启动流程与信令交互&#xff0c;关键信令包括 getRouterRtpCapabilites&#xff0c;join, createWebRtcTransport, connectWebRtcTransport, produce&#xff0c;本文将介绍 createWebRtcTransport 和 connectRtcTransport 的流…

为远程MySQL数据库配置固定的公网TCP地址【内网穿透】

在上篇文章中&#xff0c; 我们成功实现了在公网环境下远程连接内网MySQL数据库。但由于使用的免费的cpolar内网穿透&#xff0c;其所生成的公网地址为随机临时地址&#xff0c;24小时内会发生变化&#xff0c;对于需要长期远程访问的用户来讲非常不方便。因此&#xff0c;本篇…

华为云CDN加速服务,让企业用户上网“走高速”

如今CDN技术在互联网项目中越来越被广泛应用&#xff0c;虽然大多数人对于CDN并不熟悉&#xff0c;但其实我们的日常生活中的看新闻、看直播、网上购物等&#xff0c;都在无形之中跟CDN息息相关。 华为云CDN是通过部署广泛的节点服务器&#xff0c;将源站内容分发给靠近用户的智…

【修改】对“C语言实现轰炸代码”进行修改和完善

场景&#xff1a; 使用C语言实现“轰炸”效果&#xff0c;就是多条重复表情或信息的发送&#xff1b;使用场景是在QQ上面。 问题描述 1.不兼容&#xff0c;对于VS2022或者其他VS编译器无法实现效果。 2.代码能正常运行但无法弹出窗口进行发信息。 原因分析&#xff1a; 1.不…

力扣 2032. 至少在两个数组中出现的值

题目 给你三个整数数组 nums1、nums2 和 nums3 &#xff0c;请你构造并返回一个 元素各不相同的 数组&#xff0c;且由 至少 在 两个 数组中出现的所有值组成。数组中的元素可以按 任意 顺序排列。 示例 输入&#xff1a;nums1 [1,1,3,2], nums2 [2,3], nums3 [3] 输出&a…

Day843.CompletableFuture -Java 并发编程实战

CompletableFuture Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于CompletableFuture的内容。 前面不止一次提到&#xff0c;用多线程优化性能&#xff0c;其实不过就是将串行操作变成并行操作。 如果仔细观察&#xff0c;还会发现在串行转换成并行的过程中&#…

堆树和堆排序

一、堆树 1、定义 堆树的定义如下&#xff1a; &#xff08;1&#xff09;堆树是一颗完全二叉树。 &#xff08;2&#xff09;堆树的每一个结点值都大于等于或者小于等于其左右子结点的值。 &#xff08;3&#xff09;堆树中每个结点的子树都是堆树。为什么是大于等于或者小于…

一口气讲透Redis分布式缓存、秒杀 + 思维导图

一、分布式缓存 1、单点Redis的问题 1、数据丢失问题 Redis数据持久化。 2、并发能力问题 大家主从集群&#xff0c;实现读写分离。 3、故障恢复问题 利用Redis哨兵&#xff0c;实现健康检测和自动恢复。 4、存储能力问题 搭建分片集群&#xff0c;利用插槽机制实现动…

【Linux 常用监控指标总结】

1. Linux运维基础采集项 做运维&#xff0c;不怕出问题&#xff0c;怕的是出了问题&#xff0c;抓不到现场&#xff0c;两眼摸黑。所以&#xff0c;依靠强大的监控系统&#xff0c;收集尽可能多的指标&#xff0c;意义重大。但哪些指标才是有意义的呢&#xff0c;本着从实践中…

【JavaScript】定时器详解

文章目录【JavaScript】定时器详解一. 定时器分类二. 定时器的使用三. 案例&#xff1a;实现抽奖效果样式一样式二【JavaScript】定时器详解 一. 定时器分类 延迟定时器 setTimeout(function(){}, 毫秒数)作用&#xff1a;隔一段时间之后执行 间隔定时器 setInterval(functio…

【UE4 第一人称射击游戏】18-添加角色换弹时的动作

上一篇&#xff1a; 【UE4 第一人称射击游戏】17-重写换弹逻辑 本篇效果&#xff1a; 步骤&#xff1a; 1.打开“SWAT_AnimBP”&#xff0c;在动画图表中&#xff0c;添加一个名为“Reloading”的状态 完善过渡规则的连线 双击打开“Reloading”&#xff0c;添加换弹动画 2…