C#常见的设计模式-结构型模式
引言
设计模式是软件工程中用于解决常见问题的可复用解决方案。在C#编程中,常见的设计模式具有广泛的应用。本篇博客将重点介绍C#中常见的结构型设计模式,包括适配器模式、装饰器模式、代理模式、组合模式和享元模式。
目录
- 引言
- 1. 适配器模式(Adapter Pattern)
- 示例代码
- 解释
- 2. 桥接模式(Bridge Pattern)
- 示例代码
- 解释
- 3. 外观模式(Facade)
- 示例代码
- 解释
- 4. 装饰器模式(Decorator Pattern)
- 示例代码
- 解释
- 5. 代理模式(Proxy Pattern)
- 示例代码
- 解释
- 6. 组合模式(Composite Pattern)
- 示例代码
- 解释
- 7. 享元模式(Flyweight Pattern)
- 示例代码
- 解释
- 结论
1. 适配器模式(Adapter Pattern)
适配器模式用于将一个类的接口转换成客户端所期望的另一个接口。这种模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
示例代码
// 目标接口
interface ITarget
{void Request();
}// 需要被适配的类
class Adaptee
{public void SpecificRequest(){Console.WriteLine("Adaptee's SpecificRequest");}
}// 适配器类
class Adapter : ITarget
{private Adaptee _adaptee;public Adapter(Adaptee adaptee){_adaptee = adaptee;}public void Request(){_adaptee.SpecificRequest();}
}// 客户端代码
class Client
{static void Main(string[] args){Adaptee adaptee = new Adaptee();ITarget target = new Adapter(adaptee);target.Request();}
}
解释
适配器模式中的目标接口(ITarget)定义了客户端所期望的方法。Adaptee类是需要被适配的类,其中包含了一个SpecificRequest方法。Adapter类则是适配器,持有一个Adaptee对象的引用,并实现了ITarget接口。在Adapter的Request方法中,调用了Adaptee的SpecificRequest方法。在客户端代码中,创建了一个Adaptee对象和一个Adapter对象,然后通过Adapter对象去调用Request方法。
2. 桥接模式(Bridge Pattern)
桥接模式是一种结构型设计模式,用于将抽象与实现隔离开来,使它们能够独立变化。它通过组合的方式代替继承,从而降低了系统的耦合性。该模式适合在需要多个维度进行扩展时使用,例如在图形界面库中,将窗口与不同操作系统的窗口装饰风格进行分离。桥接模式的核心思想是将抽象部分与实现部分分离,使它们可以独立地变化和演化。
示例代码
// 实现部分接口
interface Implementor {void operationImpl();
}// 具体实现类A
class ConcreteImplementorA implements Implementor {@Overridepublic void operationImpl() {System.out.println("ConcreteImplementorA operation implementation");}
}// 具体实现类B
class ConcreteImplementorB implements Implementor {@Overridepublic void operationImpl() {System.out.println("ConcreteImplementorB operation implementation");}
}// 抽象部分
abstract class Abstraction {protected Implementor implementor;public void setImplementor(Implementor implementor) {this.implementor = implementor;}public abstract void operation();
}// 扩展抽象部分的具体类
class RefinedAbstraction extends Abstraction {@Overridepublic void operation() {implementor.operationImpl();}
}// 使用示例
public class BridgePatternExample {public static void main(String[] args) {Implementor implementorA = new ConcreteImplementorA();Implementor implementorB = new ConcreteImplementorB();Abstraction abstraction = new RefinedAbstraction();abstraction.setImplementor(implementorA);abstraction.operation();abstraction.setImplementor(implementorB);abstraction.operation();}
}
解释
在上述示例中,Implementor 接口定义了实现部分的操作方法。ConcreteImplementorA 和ConcreteImplementorB 是具体的实现类。Abstraction 是抽象部分的定义,其中包含一个实现部分的通用接口,并有一个抽象方法 operation() 来定义具体的操作。RefinedAbstraction 是具体的扩展抽象类,实现了抽象方法并通过组合关联了具体的实现类。
3. 外观模式(Facade)
外观模式是一种结构型设计模式,提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。。
示例代码
// 子系统A
class SubsystemA {public void operationA() {System.out.println("SubsystemA operation");}
}// 子系统B
class SubsystemB {public void operationB() {System.out.println("SubsystemB operation");}
}// 子系统C
class SubsystemC {public void operationC() {System.out.println("SubsystemC operation");}
}// 外观类
class Facade {private SubsystemA subsystemA;private SubsystemB subsystemB;private SubsystemC subsystemC;public Facade() {subsystemA = new SubsystemA();subsystemB = new SubsystemB();subsystemC = new SubsystemC();}public void operation() {subsystemA.operationA();subsystemB.operationB();subsystemC.operationC();}
}// 使用示例
public class FacadePatternExample {public static void main(String[] args) {Facade facade = new Facade();facade.operation();}
}
解释
在上述示例中,SubsystemA、SubsystemB 和 SubsystemC 是不同的子系统,它们分别提供了不同的操作。Facade 是外观类,隐藏了子系统的复杂性,为客户端提供了一个简单的接口。在外观类的操作方法中,调用了多个子系统的操作。
4. 装饰器模式(Decorator Pattern)
装饰器模式允许向一个现有对象添加新功能,同时又不改变其结构。它是通过创建一个包装对象来包裹真实对象,从而对真实对象进行功能的扩展。
示例代码
// 抽象组件接口
interface IComponent
{void Operation();
}// 具体组件类
class ConcreteComponent : IComponent
{public void Operation(){Console.WriteLine("ConcreteComponent's Operation");}
}// 抽象装饰者类
abstract class Decorator : IComponent
{protected IComponent _component;public Decorator(IComponent component){_component = component;}public virtual void Operation(){_component.Operation();}
}// 具体装饰者类
class ConcreteDecoratorA : Decorator
{public ConcreteDecoratorA(IComponent component): base(component){}public override void Operation(){base.Operation();AddedBehavior();}private void AddedBehavior(){Console.WriteLine("ConcreteDecoratorA's AddedBehavior");}
}class ConcreteDecoratorB : Decorator
{public ConcreteDecoratorB(IComponent component): base(component){}public override void Operation(){base.Operation();AddedBehavior();}private void AddedBehavior(){Console.WriteLine("ConcreteDecoratorB's AddedBehavior");}
}// 客户端代码
class Client
{static void Main(string[] args){IComponent component = new ConcreteComponent();component = new ConcreteDecoratorA(component);component = new ConcreteDecoratorB(component);component.Operation();}
}
解释
装饰器模式中的抽象组件接口(IComponent)定义了被装饰者和装饰者之间的公共方法。ConcreteComponent类是具体的组件类,实现了IComponent接口的Operation方法。Decorator类是抽象装饰者类,持有一个IComponent对象的引用,并实现了IComponent接口。ConcreteDecoratorA和ConcreteDecoratorB类分别是具体装饰者类,它们继承自Decorator类,并在调用父类Operation方法的同时添加了额外的行为。
在客户端代码中,首先创建了一个ConcreteComponent对象,然后通过多次进行装饰,分别使用ConcreteDecoratorA和ConcreteDecoratorB对其进行包装。最后调用component.Operation()方法时,实际上会调用被装饰者的Operation方法,并在其基础上添加了额外的行为。
5. 代理模式(Proxy Pattern)
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式主要通过代理类来封装目标对象,控制客户端对目标对象的访问,并在必要的时候进行一些预处理或后处理操作。
示例代码
// 被代理接口
interface ISubject
{void Request();
}// 真实对象类
class RealSubject : ISubject
{public void Request(){Console.WriteLine("RealSubject's Request");}
}// 代理类
class Proxy : ISubject
{private RealSubject _realSubject;public void Request(){if (_realSubject == null){_realSubject = new RealSubject();}PreProcess();_realSubject.Request();PostProcess();}private void PreProcess(){Console.WriteLine("Proxy's PreProcess");}private void PostProcess(){Console.WriteLine("Proxy's PostProcess");}
}// 客户端代码
class Client
{static void Main(string[] args){ISubject proxy = new Proxy();proxy.Request();}
}
解释
代理模式中的被代理接口(ISubject)定义了代理对象和真实对象的公共方法。RealSubject类是真实对象类,实现了被代理接口的Request方法。Proxy类是代理类,持有一个RealSubject对象的引用,并实现了被代理接口的Request方法。在Proxy类的Request方法中,进行了预处理、调用真实对象的Request方法和后处理。
在客户端代码中,创建了一个代理对象Proxy,然后通过该对象调用Request方法。在调用过程中,会对真实对象进行实例化,并在方法执行前后进行相应的预处理和后处理。
6. 组合模式(Composite Pattern)
组合模式将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。
示例代码
// 抽象组件类
abstract class Component
{protected string _name;public Component(string name){_name = name;}public abstract void Display();
}// 叶子节点类
class Leaf : Component
{public Leaf(string name): base(name){}public override void Display(){Console.WriteLine(_name);}
}// 容器节点类
class Composite : Component
{private List<Component> _children = new List<Component>();public Composite(string name): base(name){}public void Add(Component component){_children.Add(component);}public void Remove(Component component){_children.Remove(component);}public override void Display(){Console.WriteLine(_name);foreach (Component component in _children){component.Display();}}
}// 客户端代码
class Client
{static void Main(string[] args){Composite root = new Composite("root");Leaf leaf1 = new Leaf("leaf1");Leaf leaf2 = new Leaf("leaf2");Composite composite1 = new Composite("composite1");Composite composite2 = new Composite("composite2");root.Add(leaf1);root.Add(composite1);composite1.Add(leaf2);composite1.Add(composite2);root.Display();}
}
解释
组合模式中的抽象组件类(Component)定义了树状结构中所有对象的通用行为的接口。Leaf类是叶子节点类,它继承自Component类,并实现了Display方法。Composite类是容器节点类,它继承自Component类,并持有一组Component对象。在Composite类的Display方法中,首先输出自身信息,然后递归调用所有子节点的Display方法。
在客户端代码中,首先创建了一个根节点root和一些叶子节点和容器节点。通过调用容器节点的Add方法可以将其他节点添加到其内部。最后调用root.Display()方法,会递归地展示整个树状结构。
7. 享元模式(Flyweight Pattern)
享元模式是一种池技术,主要用于减少创建对象的数量,以减少内存占用和提高性能。享元模式通过共享已创建的对象,避免重复创建相同的对象。
示例代码
// 享元接口
interface IFlyweight
{void Operation();
}// 具体享元类
class ConcreteFlyweight : IFlyweight
{private readonly string _intrinsicState;public ConcreteFlyweight(string intrinsicState){_intrinsicState = intrinsicState;}public void Operation(){Console.WriteLine($"ConcreteFlyweight's Operation with {_intrinsicState}");}
}// 享元工厂类
class FlyweightFactory
{private Dictionary<string, IFlyweight> _flyweights = new Dictionary<string, IFlyweight>();public IFlyweight GetFlyweight(string key){if (_flyweights.ContainsKey(key)){return _flyweights[key];}else{IFlyweight flyweight = new ConcreteFlyweight(key);_flyweights.Add(key, flyweight);return flyweight;}}
}// 客户端代码
class Client
{static void Main(string[] args){FlyweightFactory factory = new FlyweightFactory();IFlyweight flyweight1 = factory.GetFlyweight("key1");flyweight1.Operation();IFlyweight flyweight2 = factory.GetFlyweight("key2");flyweight2.Operation();IFlyweight flyweight3 = factory.GetFlyweight("key1");flyweight3.Operation();}
}
解释
享元模式中的享元接口(IFlyweight)定义了享元类的公共方法。ConcreteFlyweight类是具体享元类,它实现了IFlyweight接口,并持有一个内部状态(_intrinsicState)。FlyweightFactory类是享元工厂类,用于创建和管理享元对象。
在客户端代码中,首先创建了一个FlyweightFactory对象。通过调用工厂的GetFlyweight方法可以获取享元对象,如果对象已经存在,则直接返回已有对象;如果对象不存在,则创建新的享元对象并将其缓存起来。最后调用享元对象的Operation方法时,会输出其内部状态。

结论
结构型设计模式在C#编程中具有广泛的应用。适配器模式用于解决不兼容接口的问题,装饰器模式用于动态地扩展对象的功能,代理模式用于控制对对象的访问,组合模式用于处理树状结构数据,享元模式用于减少对象创建的数量。合理使用这些结构型设计模式可以提高代码的可读性、可维护性和可扩展性。
参考资料:
- Design Patterns in C#
相关文章:
C#常见的设计模式-结构型模式
引言 设计模式是软件工程中用于解决常见问题的可复用解决方案。在C#编程中,常见的设计模式具有广泛的应用。本篇博客将重点介绍C#中常见的结构型设计模式,包括适配器模式、装饰器模式、代理模式、组合模式和享元模式。 目录 引言1. 适配器模式(Adapter …...
Redis分片备库切换操作
Redis分片备库切换操作 场景描述: 分片集群: 1.ipa:5001-ipa:5002 2.ipb:5001-ipb:5002 需将两个分片备库互置完成灾备 操作步骤 准备工作 主机密码:1qaz!QAZ 获取节点信息命令 /redispath/bin/redis-cli -a password -h ip -p port red…...
二叉树:leetcode1457. 二叉树中的伪回文路径
给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。 请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。 给定二叉树的节点数目…...
【【Linux下的Petallinux 以及其他的配置】】
Linux下的Petallinux 以及其他的配置 sudo apt-get install iproute2 gawk python3 python build-essential gcc git make net-tools libncurses5-dev tftpd zlib1g-dev libssl-dev flex bison libselinux1 gnupg wget git-core diffstat chrpath socat xterm autoconf libtoo…...
13、深度学习之神经网络
深度学习是机器学习中重要的一个学科分支,它的特点就在于需要构建多层“深度”的神经网络。 人们在探索人工智能初期,就曾设想构建一个用数学方式来表达的模型,它可以模拟人的大脑,大脑我们都知道,有很多神经元,每个神经元之间通过突触链接。 神经网络的设计就是模仿了这…...
js的数组去重方法
目录 es6数组中对象去重 1. filter()用法 2. findIndex()用法 3. 去重 其他方法: 方法二:reduce()去重 1. reduce()用法 1.1 找出字符长度最长的数组成员。 1.2 扁平化二维数组 1.3 扁平化多维数组 三、总结方案: 使用Set…...
在 Next 14 的 appRouter 模式中接入 React-Redux
在 Next 14 的 appRouter 模式中接入 React-Redux 说明 Next.js 版本升级到 14 后,相比 13 版本是一个改动很大的大版本升级,很多概念或者使用方式 13 版本都有较大的区别,因此这里记录一些学习 14 版本的 Next.js 的心得体会或者问题。因为…...
aspose-words 跳过证书验证jar
优先用 aspose-words-19.3.jar ,不需要读取license.xml,导出后直接水印,jar包最好直接放在项目resource目录下直接引用,要不下载不下来 public static String doc2pdf(String fileName, String filePath) {try {String oldFile f…...
【开题报告】基于uniapp的瑜伽学习交流小程序的设计与实现
1.选题背景 瑜伽在现代社会中越来越受到人们的关注和喜爱。它不仅可以帮助人们塑造健美的身材,还能促进身心健康、提高生活质量。然而,由于瑜伽动作的复杂性和技巧性,很多初学者在学习过程中会遇到困难和挑战。 同时,由于工作和…...
【蓝桥杯单片机】应用手势传感器(串口2)
手势传感器:串口通信,可以识别左滑、右滑、单击三种手势,输出相应的固定串口数据。 控制器:IAP15F2K61S2单片机。 引脚连接: 单片机 手势传感器 P46 -> TX P47 -> RX VCC -> 5V GND->gnd main.c 程序说明:传感器与单片机的串口2进行数据交互,这里使用的是开…...
51单片机蜂鸣器发出悦耳的声音
51单片机蜂鸣器发出悦耳的声音 1.概述 这篇文章介绍单片机控制蜂鸣器入门小实验,通过该实验掌握蜂鸣器发声的原理,控制声音发出我们想听的音乐。 2.蜂鸣器发声 2.1.硬件原理 1.蜂鸣器正极接单片机20号引脚VCC,负极接19号引脚P1.7 2.20MH…...
Web3.0时代:区块链DAPP将如何颠覆传统模式
小编介绍:10年专注商业模式设计及软件开发,擅长企业生态商业模式,商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地;扶持10余个电商平台做到营收过千万,数百个平台达到百万会员,欢迎咨询。 随着…...
JAVA 算法面试总结
1、二分查找 二分查找又叫折半查找,要求待查找的序列有序。每次取中间位置的值与待查关键字比较,如果中间位置 的值比待查关键字大,则在前半部分循环这个查找的过程,如果中间位置的值比待查关键字小, 则在后半部分循环…...
【Docker】安装MySQL 通俗易懂 亲测没有任何问题
目录 1.拉取镜像 2.运行容器 3.创建mysql配置文件 4.测试 1.拉取镜像 dockerhub官网:Docker 如果需要其他版本mysql docker pull mysql:xxx(版本) docker pull mysql #默认拉取最新版本 latest 2.运行容器 docker run -d -p 3306:33…...
【React】打包优化-配置CDN
CDN 是一种内容分发网络服务,当用户请求网站内容时,由离用户最近的服务器将缓存的资源内容传递给用户。 哪些资源可以放到CDN服务器?(比如react、 react-dom) 体积较大,需要利用CDN文件在浏览器的缓存特性…...
上手 Promethus - 开源监控、报警工具包
名词解释 Promethus 是什么 开源的【系统监控和警报】工具包 专注于: 1)可靠的实时监控 2)收集时间序列数据 3)提供强大的查询语言(PromQL),用于分析这些数据 功能: 1࿰…...
Linux学习教程(第十二章 Linux系统管理)三
第十二章 Linux系统管理(进程管理、工作管理和系统定时任务)(三) 十九、Linux 定时执行任务(at命令) Linux at命令详解:定时执行任务 要想使用 at 命令,读者需提前安装好 at 软件…...
网络篇---第三篇
系列文章目录 文章目录 系列文章目录前言一、说一下HTTP的长连接与短连接的区别二、TCP 为什么要三次握手,两次不行吗?为什么?三、说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大…...
tensorflow和pytorch的联系与区别
TensorFlow和PyTorch是两个流行的深度学习框架,它们在很多方面都有相似之处,因为它们都旨在解决相同的问题,即构建和训练神经网络。 以下是它们之间的一些联系: 1.深度学习框架: TensorFlow和PyTorch都是开源的深度学…...
为什么选择美国VPS服务器
企业、个人和组织都需要一个稳定高效的服务器来托管他们的网站、应用程序和数据。而对于中国用户来说,寻找一个性价比高的便宜美国VPS服务器,既能满足需求,又能节约成本,成为了一个非常重要的问题。 VPS即虚拟专用服务器…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

