设计模式-组合模式和建筑者模式详解
一. 组合模式
1. 背景
在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,如果用组合模式来实现会很方便。
2. 定义和特点
(1). 定义:有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。
(2). 优点:
A. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
B. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;
(3). 缺点
A. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
B. 不容易限制容器中的构件;
C. 不容易用继承的方法来增加构件的新功能;
3. 具体实现
(1). 模式结构
可以自身嵌套结构。
(2). 使用场景
存储上下级关系,CEO→技术主管→员工;CEO→销售主管→员工。
(3). 代码实操
上下级自身嵌套代码:
/// <summary>/// 员工类/// </summary>public class Employee{private string name;private string dept;private int salary;//代表下级子类private List<Employee> subordinates;//构造函数public Employee(string name, string dept, int sal){this.name = name;this.dept = dept;this.salary = sal;subordinates = new List<Employee>();}public void add(Employee e){subordinates.Add(e);}public void remove(Employee e){subordinates.Remove(e);}public List<Employee> getSubordinates(){return subordinates;}public string toString(){return ("Employee :[ Name : " + name+ ", dept : " + dept + ", salary :"+ salary + " ]");}}
测试代码:
{// 1、树形机构的场景,使用组合模式Employee CEO = new Employee("张三", "CEO", 30000);Employee headMarketing = new Employee("李四", "技术经理", 20000);Employee headSales = new Employee("王五", "销售经理", 20000);Employee clerk1 = new Employee("赵六", "销售", 10000);Employee clerk2 = new Employee("钱七", "销售", 10000);Employee salesExecutive1 = new Employee("Tony", "技术", 10000);Employee salesExecutive2 = new Employee("Mark", "技术", 10000);CEO.add(headSales);CEO.add(headMarketing);headSales.add(clerk1);headSales.add(clerk2);headMarketing.add(salesExecutive1);headMarketing.add(salesExecutive2);//打印该组织的所有员工Console.WriteLine(CEO.toString());foreach (Employee headEmployee in CEO.getSubordinates()){Console.WriteLine(headEmployee.toString());foreach (Employee employee in headEmployee.getSubordinates()){Console.WriteLine(employee.toString());}}}
运行结果:
4. 适用场景分析
A. 在需要表示一个对象整体与部分的层次结构的场合。
B. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。
更多C++后台开发技术点知识内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开发,Linux内核,TCP/IP,协程,DPDK多个高级知识点。
C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址
【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取

二. 建筑者模式
1. 背景
在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。例如,计算机是由 OPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。
生活中这样的例子很多,如游戏中的不同角色,其性别、个性、能力、脸型、体型、服装、发型等特性都有所差异;还有汽车中的方向盘、发动机、车架、轮胎等部件也多种多样;每封电子邮件的发件人、收件人、主题、内容、附件等内容也各不相同。
以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。
2. 定义和特点
(1). 定义
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
(2). 优点
A. 各个具体的建造者相互独立,有利于系统的扩展。
B. 客户端不必知道产品内部组成的细节,便于控制细节风险。
(3). 缺点
A. 产品的组成部分必须相同,这限制了其使用范围。
B. 如果产品的内部变化复杂,该模式会增加很多的建造者类。
(4). 与工厂方法模式的区别
建造者模式注重零部件的组装过程,而工厂方模式更注重零部件的创建过程,但两者可以结合使用。
3. 具体实现
(1). 模式结构
建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成。
A. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
B. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
C. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
D. 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
PS:如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。
结构图如下:
(2). 使用场景
现在要构建自行车,包括核心组件frame、seat、tire,而每个组件可选的材料有多种,自行车的构建顺序是固定的,比如按照这个顺序:BuidFrame、BuildSeat、BuildTire。这个场景就可以使用建筑者模式。
(3). 代码实操
各种自行车材料代码:
/// <summary>/// 自行车框架/// </summary>public interface IFrame{void show();}/// <summary>/// 自行车座椅/// </summary>public interface ISeat{void show();}/// <summary>/// 自行车轮胎/// </summary>public interface ITire{void show();}/// <summary>/// 合金自行车框架1/// </summary>public class AlloyFrame1 : IFrame{public void show(){Console.WriteLine("我是合金自行车框架1");}}/// <summary>/// 合金自行车框架2/// </summary>public class AlloyFrame2 : IFrame{public void show(){Console.WriteLine("我是合金自行车框架2");}}/// <summary>/// 真皮座椅1/// </summary>public class DermisSeat1 : ISeat{public void show(){Console.WriteLine("我是真皮座椅1");}}/// <summary>/// 真皮座椅2/// </summary>public class DermisSeat2 : ISeat{public void show(){Console.WriteLine("我是真皮座椅2");}}/// <summary>/// 结实的轮胎1/// </summary>public class SolidTire1 : ITire{public void show(){Console.WriteLine("我是结实的轮胎1");}}/// <summary>/// 结实的轮胎2/// </summary>public class SolidTire2 : ITire{public void show(){Console.WriteLine("我是结实的轮胎2");}}
自行车代码:
/// <summary>/// 自行车类/// </summary>public class Bike{/// <summary>/// 自行车框架/// </summary>public IFrame frame { set; get; }/// <summary>/// 自行车座椅/// </summary>public ISeat seat { set; get; }/// <summary>/// 自行车 轮胎/// </summary>public ITire tire { set; get; }/// <summary>/// 获取自行车的详情信息/// </summary>public void GetDetils(){Console.WriteLine("自行车的详细信息如下:");frame.show();seat.show();tire.show();}}
抽象建筑者和具体建筑者:
/// <summary>/// 抽象建筑者类/// 如果只有一个具体的建筑者类,则可以省略该抽象建筑者类的/// </summary>public abstract class AbstractBuilder{public Bike mBike = new Bike();public abstract void BuildFrame();public abstract void BuildSeat();public abstract void BuildTire();/// <summary>/// 返回自行车对象/// </summary>/// <returns></returns>public abstract Bike Build();}/// <summary>/// 自行车建筑者类1/// </summary>public class BikeBuilder1: AbstractBuilder{/// <summary>/// 构建frame/// </summary>public override void BuildFrame(){mBike.frame = new AlloyFrame1();}/// <summary>/// 构建seat/// </summary>public override void BuildSeat(){mBike.seat = new DermisSeat1();}/// <summary>/// 构建tire/// </summary>public override void BuildTire(){mBike.tire = new SolidTire1();}/// <summary>/// 返回直行车对象/// </summary>/// <returns></returns>public override Bike Build(){return mBike;}}/// <summary>/// 自行车建筑者类2/// </summary>public class BikeBuilder2 : AbstractBuilder{/// <summary>/// 构建frame/// </summary>public override void BuildFrame(){mBike.frame = new AlloyFrame2();}/// <summary>/// 构建seat/// </summary>public override void BuildSeat(){mBike.seat = new DermisSeat2();}/// <summary>/// 构建tire/// </summary>public override void BuildTire(){mBike.tire = new SolidTire2();}/// <summary>/// 返回直行车对象/// </summary>/// <returns></returns>public override Bike Build(){return mBike;}}
指挥者:
/// <summary>/// 指挥者/// 调用建造者中的方法完成复杂对象的创建/// 如果只有一个建筑者的话,可以省略该指挥者的角色/// </summary>public class BikeDirector{private AbstractBuilder _builder;public BikeDirector(AbstractBuilder builder){this._builder = builder;}/// <summary>/// Bike的构建和组装/// </summary>/// <returns></returns>public Bike CreateBike(){_builder.BuildFrame();_builder.BuildSeat();_builder.BuildTire();return _builder.Build();}}
测试代码:
//1.普通模式{Console.WriteLine("-------------------下面是普通模式构建自行车-------------------------");//1. 构建自行车Bike b = new Bike();b.frame = new AlloyFrame1();b.seat = new DermisSeat2();b.tire = new SolidTire1();//2. 输出自行车信息b.GetDetils();}//2. 使用建筑者模式{Console.WriteLine("-------------------下面是使用建筑者模式构建自行车-------------------------");//1. 构建建筑者BikeBuilder1 builder = new BikeBuilder1();builder.BuildFrame();builder.BuildSeat();builder.BuildTire();//2. 构建自行车Bike bike = builder.Build();//3. 输出自行车的信息bike.GetDetils();}//3. 引入抽象建筑者父类{Console.WriteLine("-------------------下面是 引入抽象建筑者父类 构建自行车-------------------------");//1. 构建建筑者1AbstractBuilder builder = new BikeBuilder1();builder.BuildFrame();builder.BuildSeat();builder.BuildTire();//2. 构建自行车Bike bike = builder.Build();//3. 输出自行车的信息bike.GetDetils();//1. 构建建筑者2AbstractBuilder builder2 = new BikeBuilder2();builder2.BuildFrame();builder2.BuildSeat();builder2.BuildTire();//2. 构建自行车Bike bike2 = builder2.Build();//3. 输出自行车的信息bike2.GetDetils();}//4. 引入指挥者{Console.WriteLine("-------------------下面是 引入指挥者 构建自行车-------------------------");//指挥者1BikeDirector dirctor1 = new BikeDirector(new BikeBuilder1());Bike bike1 = dirctor1.CreateBike();bike1.GetDetils();//指挥者2BikeDirector dirctor2 = new BikeDirector(new BikeBuilder2());Bike bike2 = dirctor2.CreateBike();bike2.GetDetils();}
运行效果:

4. 适用场景分析
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
A. 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
B. 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
原文链接:https://www.cnblogs.com/yaopengfei/p/13462519.html
相关文章:

设计模式-组合模式和建筑者模式详解
一. 组合模式 1. 背景 在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如&…...
Pcap文件的magic_number
1. 简述 pcap文件头中的magicNum是来标识pcap文件文件头和包头字节序和应用是否一致的。 在标准情况下为0xa1b2c3d4。如果相反则说明需要调换字节序。 一般格式 Global Header Packet Header Packet Data Packet Header Packet Data ....pcap文件头格式 typedef struct pca…...

MDS75-16-ASEMI三相整流模块MDS75-16
编辑-Z MDS75-16在MDS封装里采用的6个芯片,是一款工业焊机专用大功率整流模块。MDS75-16的浪涌电流Ifsm为920A,漏电流(Ir)为5mA,其工作时耐温度范围为-40~150摄氏度。MDS75-16采用GPP硅芯片材质,里面有6颗芯片组成。MDS75-16的电…...

基本TCP编程
1. 基本概念 TCP (即传输控制协议) 是一种面向连接的传输层协议,它能提供高可靠性通信 (即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。 2. 通信流程解析 TCP 通信的流程与打电话的过程相似,以下以一对情侣打电话的过程来展示TCP的通信流程: 其中服务端 …...

【沁恒WCH CH32V307V-R1开发板读取板载温度实验】
【沁恒WCH CH32V307V-R1开发板读取板载温度实验】1. 前言2. 软件配置2.1 安装MounRiver Studio3. ADC项目测试3.1 打开ADC工程3.2 编译项目4. 下载验证4.1 接线4.2 演示效果5. 小结1. 前言 ADC 模块包含 2 个 12 位的逐次逼近型的模拟数字转换器,最高 14MHz 的输入时…...

学习SpringCloudAlibaba(二)微服务的拆分与编写
目录 一、单体架构VS微服务架构 1.单体架构 (1).单体架构的优点 (2).单体架构的缺点 2.微服务架构 (1)微服务的特性 (2)微服务架构图 (3)微服务的优点 …...

通过对HashMap的源码分析解决部分关于HashMap的问题
HashMap第一次分配多大的空间我们查看resize()中的源码所以当我们没有传入默认容量的参数的时候,默认容量是16当传进一个20的初始参数时,数组的容量是多大所以当我们传入20的参数,这时创建的容量是32(2^5)对…...
【无标题】
Windeployqt 打包,缺少DLL 的原因分析,解决方法 很多同学使用工具windeployqt进行打包发布后,运行exe文件时,还是会出现下图所示的系统错误提示,这种情况就表示相关的DLL 库文件没有被正确打包。可是windeployqt明确显示运行正常啊,难道是QT自家的windeployqt这个工具有…...

渗透测试 -- 网站信息收集
数据来源 01 网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言(php、java、...)、数据库(Mysql、...)为什么要了解这些? 举个例子:发现了一…...

Windows 搭建ARM虚拟机 UOS系统
搭建环境安装虚拟机下载虚拟机QEMU,https://www.qemu.org/download/,目前最新版本是7.2.0。安装完成后,需要将qemu的安装路径设置到环境变量完成后运行cmd,测试环境变量配置完成。qemu-system-aarch64 --version如上截图所示&…...
day58每日温度_下一个更大元素1
力扣739.每日温度 题目链接:https://leetcode.cn/problems/daily-temperatures/ 思路 什么时候用单调栈呢? 通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了…...

超清遥感影像语义分割处理
分割出城市中的垃圾堆场,遂寻找到了 UrbanAtlas 2012 database 这个数据集和对应的 baseline baseline IoU for class 1: 0.5667 IoU for class 2: 0.3504 IoU for class 3: 0.0001 IoU for class 4: 0.0002 IoU for class 5: 0.4121 IoU for class 6: 0.0204 IoU for cla…...

RabbitMQ安装及配置
目录1.下载和安装1.1 下载1.2. 安装1.3 测试1.4 卸载管理界面2.1 添加用户2.2 创建Virtual Hosts2.3. 设置权限1.下载和安装 1.1 下载 1.下载Erlang的rpm包 RabbitMQ是Erlang语言编写,所以Erang环境必须要有,注:Erlang环境一定要与RabbitMQ…...

网络协议(四):网络互联模型、物理层、数据链路层
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络互联模型、物理层、数据链路层 目录一、网…...
请问有没有关于数据预测的方法?
利用数据对未来进行预测分析,虽然不能百分百的准确预测,但是有数据理论支撑的趋势预测是客观可靠的。当数据分析的目的涉及未来决策时,就可以大胆使用预测的思路和方法,如企业明年的战略计划、销售计划等,这对企业而言…...
[CVPR 2021] Your “Flamingo“ is My “Bird“: Fine-Grained, or Not
Contents Your "Flamingo" is My "Bird"MethodCooperation or Confrontation?Disentanglement and ReinforcementExperimentDiscussionsReferencesYour “Flamingo” is My “Bird” 对于如下图片,FGVC 的目标是让模型识别出 “flamingo”,但对于大部分…...
clickHouse笔记
1、介绍 clickHouse将数据进行分成多个partition,多个CUP进行进行单条的Query,不适合qps特别高的查询场景;适应场景:处理过的,字段特别大的宽表,进行统计,查询,聚合等数据分析场景 …...

10.jQuery中请求预处理 $.ajaxPrefilter()
在使用jQuery发起请求的时候($.get(),$.post().$ajax()都可以)会默认在请求前调用$.ajaxPrefilter()这个函数,我们可以利用这个来做一些事情 目录 1 定义API根路径 2 添加请求头 3 添加请求结束的回调函数 1 定义API根路径 这样后面每次请求就不用再写根路…...
【黄啊码】浅谈PHP入门|如何学习PHP
大家好,我是黄啊码,很多小白问我,怎么入门PHP,甚至连PHP能干嘛都不知道,今天啊码就具体来讲讲。 什么是PHP PHP是一种开源的通用脚本语言,用于创建动态网页和应用程序。它可以运行在服务器端,…...

人大金仓数据库的归档日志
归档日志 归档日志是非活动的WAL日志备份。通过使用归档日志,可以保留所有WAL日志的历史记录,当数据库处于ARCHIVELOG模式并进行日志切换时,后台进程archiver process会将WAL日志的内容保存到归档日志中,当数据库出现介质失败时&…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...