23种设计模式简单记录

23种设计模式主要分为三大类:创建型模式、结构型模式和行为型模式。下面是这些设计模式的概览:

创建型模式(Creational Patterns)

  1. 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
  2. 工厂方法模式(Factory Method):定义一个用于创建对象的接口,但让子类决定实例化哪一个类。
  3. 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
  4. 建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  5. 原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。

结构型模式(Structural Patterns)

  1. 适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口。
    1. MusicPlayerAdapter 类作为适配器,它实现了 PlayMusicV2 接口,并在内部持有一个 PlayMusicV1 对象的引用。当客户端调用 play 方法时,适配器会根据传入的参数调用旧接口的 playMp3 方法,从而实现了接口的转换,让旧的音频播放器库能够适应新的应用程序接口。例子:
      // 原有的接口
      interface PlayMusicV1 {
          void playMp3(String filename);
      }
      
      // 新的接口
      interface PlayMusicV2 {
          void play(String audioType, String filename);
      }
      
      // 第三方库的实现类
      class OldMusicPlayer implements PlayMusicV1 {
          @Override
          public void playMp3(String filename) {
              System.out.println("Playing MP3 file: " + filename);
          }
      }
      
      // 适配器类
      class MusicPlayerAdapter implements PlayMusicV2 {
          private final PlayMusicV1 player;
      
          public MusicPlayerAdapter(PlayMusicV1 player) {
              this.player = player;
          }
      
          @Override
          public void play(String audioType, String filename) {
              if ("mp3".equalsIgnoreCase(audioType)) {
                  player.playMp3(filename);
              } else {
                  System.out.println("Unsupported audio type: " + audioType);
              }
          }
      }
      
      // 客户端代码
      public class Client {
          public static void main(String[] args) {
              PlayMusicV1 oldPlayer = new OldMusicPlayer();
              PlayMusicV2 adapter = new MusicPlayerAdapter(oldPlayer);
              
              // 使用新接口播放MP3
              adapter.play("mp3", "favorite_song.mp3");
          }
      }

  2. 桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们都可以独立地变化。
  3. 组合模式(Composite):允许你将对象组合成树形结构来表示整体/部分层次结构。
  4. 装饰器模式(Decorator):动态地给一个对象添加一些额外的职责。
  5. 外观模式(Facade):为子系统中的一组接口提供一个一致的界面,简化接口。
  6. 享元模式(Flyweight):运用共享技术有效支持大量细粒度的对象。
  7. 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
    1. 代理模式通过提供一个代理对象来控制对真实对象的访问,这个代理对象可以在访问真实对象前进行一些预处理操作,或者在访问后进行一些后续处理。下面是一个简单的Java代理模式示例,我们以租房为例,说明静态代理和动态代理的实现。

      静态代理示例

      首先定义一个租房服务的接口:

      1public interface RentHouse {
      2    void rent();
      3}

      接着实现这个接口的真实对象(房东):

      1public class RealEstate implements RentHouse {
      2    @Override
      3    public void rent() {
      4        System.out.println("房东出租房子");
      5    }
      6}

      然后创建一个静态代理类,也实现相同的接口:

      1public class HouseAgency implements RentHouse {
      2    private RealEstate realEstate;
      3
      4    public HouseAgency(RealEstate realEstate) {
      5        this.realEstate = realEstate;
      6    }
      7
      8    @Override
      9    public void rent() {
      10        preProcess();
      11        realEstate.rent();
      12        postProcess();
      13    }
      14
      15    private void preProcess() {
      16        System.out.println("中介进行房源展示、咨询等前期工作");
      17    }
      18
      19    private void postProcess() {
      20        System.out.println("中介完成合同签订等后续工作");
      21    }
      22}

      最后是客户端代码,使用代理来租房:

      1public class Client {
      2    public static void main(String[] args) {
      3        RealEstate realEstate = new RealEstate();
      4        RentHouse proxy = new HouseAgency(realEstate);
      5        proxy.rent();
      6    }
      7}

      动态代理示例

      动态代理通常使用Java的java.lang.reflect.Proxy类来创建代理对象,这里使用JDK动态代理为例:

      首先,保持RentHouse接口和RealEstate类不变。

      动态代理类如下:

      1import java.lang.reflect.InvocationHandler;
      2import java.lang.reflect.Method;
      3import java.lang.reflect.Proxy;
      4
      5public class DynamicProxy implements InvocationHandler {
      6    private Object target;
      7
      8    public Object bind(Object target) {
      9        this.target = target;
      10        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
      11                target.getClass().getInterfaces(), this);
      12    }
      13
      14    @Override
      15    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      16        preProcess();
      17        Object result = method.invoke(target, args);
      18        postProcess();
      19        return result;
      20    }
      21
      22    private void preProcess() {
      23        System.out.println("动态代理:中介进行房源展示、咨询等前期工作");
      24    }
      25
      26    private void postProcess() {
      27        System.out.println("动态代理:中介完成合同签订等后续工作");
      28    }
      29}

      客户端代码调整为:

      1public class Client {
      2    public static void main(String[] args) {
      3        RealEstate realEstate = new RealEstate();
      4        DynamicProxy dynamicProxy = new DynamicProxy();
      5        RentHouse proxy = (RentHouse) dynamicProxy.bind(realEstate);
      6        proxy.rent();
      7    }
      8}

      在这个例子中,无论是静态代理还是动态代理,代理对象都在真实对象执行租房操作前后增加了额外的行为,如房源展示、合同签订等,体现了代理模式的价值。动态代理相比静态代理更加灵活,可以在运行时动态创建代理对象,无需为每个真实对象都手动创建一个代理类。

行为型模式(Behavioral Patterns)

  1. 责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
  2. 命令模式(Command):将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。
  3. 解释器模式(Interpreter):给定一种语言,定义它的文法和一个解释器,该解释器使用该语法来解释语言中的句子。
  4. 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。
  5. 中介者模式(Mediator):用一个中介者对象来封装一系列的对象交互。
  6. 备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
  7. 观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
  8. 状态模式(State):允许一个对象在其内部状态改变时改变它的行为。
  9. 策略模式(Strategy):定义一系列算法,把它们一个个封装起来,并使它们可以相互替换。
  10. 模板方法模式(Template Method):定义一个操作中的算法骨架,而将一些步骤延迟到子类中实现。
  11. 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【哈希】Leetcode 面试题 01.02. 判定是否互为字符重排

题目讲解 面试题 01.02. 判定是否互为字符重排 算法讲解 直观的想法:我们找到一个字符串的全排列,然后对比当前的排列是否等于另一个字符串。如果两个字符串如果互为排列,所以我们知道两个字符串对应的字符出现的个数相同,那么…

在config.json文件中配置出来new mars3d.graphic.PolylineCombine({大量线合并渲染类型的geojson图层

在config.json文件中配置出来new mars3d.graphic.PolylineCombine({大量线合并渲染类型的geojson图层 问题场景: 1.浏览官网示例的时候图层看到大量线数据合并渲染的示例 2.矢量数据较大量级的时候,这种时候怎么在config.json文件中尝试配置呢&#x…

高并发内存池: 介绍

一.功能介绍 功能: 用于实现高效的多线程内存管理(替代系统的内存分配相关的函数(malloc, free)) 性能的提升: 池化技术, 锁竞争的减小处理内存碎片: 内碎片, 外碎片 池化技术: 概念:预先向系统申请过量的资源, 自己管理.->提高性能(每次申请资源都有较大的开销, 提前申…

数字文旅重塑旅游发展新生态:以数字化转型为契机,推动旅游产业的创新发展,提升旅游服务的智能化、网络化和个性化水平

目录 一、引言 二、数字化转型推动旅游产业创新发展 1、数字化转型提升旅游产业效率 2、数字化转型拓展旅游产业边界 3、数字化转型促进旅游产业可持续发展 三、提升旅游服务智能化、网络化和个性化水平 1、智能化提升旅游服务体验 2、网络化拓宽旅游服务渠道 3、个性…

OpenHarmony实战开发-多层级手势事件

多层级手势事件指父子组件嵌套时,父子组件均绑定了手势或事件。在该场景下,手势或者事件的响应受到多个因素的影响,相互之间发生传递和竞争,容易出现预期外的响应。 本章主要介绍了多层级手势事件的默认响应顺序,以及…

【大学生电子竞赛题目分析】——2023年H题《信号分离装置》

今年的大赛已临近落幕,笔者打算陆续对几个熟悉领域的题目作一番分析与讨论,今天首先分析H题。 网上有一些关于H题的分析,许多都是针对盲信号分析的。然而本题具有明确的信号频率范围,明确的信号可能频率,明确的信号波…

全栈从0到1 3D旅游地图标记和轨迹生成

功能演示 演示视频 体验地址 Vercel App 开发技术栈: NextJs(前端框架)React(前端框架)TailwindCSS (CSS样式)echart echart gl (地图生成)shadui(UI组件…

HTML5本地存储账号密码

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>HTML5本地存储账号密码</title> </head…

[论文笔记]SEARCHING FOR ACTIVATION FUNCTIONS

引言 今天带来另一篇激活函数论文SEARCHING FOR ACTIVATION FUNCTIONS的笔记。 作者利用自动搜索技术来发现新的激活函数。通过结合详尽的搜索和基于强化学习的搜索&#xff0c;通过实验发现最佳的激活函数 f ( x ) x ⋅ sigmoid ( β x ) f(x) x \cdot \text{sigmoid}(βx…

Android 学习 鸿蒙HarmonyOS 4.0 第二天(项目结构认识)

项目结构认识 和 了解&#xff1a; 工程目录下的结构如下&#xff1a; 首先能看到有两个.开头的文件&#xff0c;分别是.hvigor 和 .idea。这两个文件夹都是与构建有关系的&#xff0c; 如果你开发过安卓app&#xff0c;构建完会生成一个apk安装包&#xff0c;鸿蒙则是生成hap…

android 分区存储(沙盒存储)适配总结

目录 一、分区存储概念 1.外部存储分类 2.分区存储如何影响文件访问 二、分区适配方案 1. 应用分区存储的文件访问规定 (1).应用专属目录--私有目录 (2).共享目录文件--公有目录 2.MediaStore API介绍 3.Storage Access Framework介绍 三、所有文件访问权限 四、总结…

急急急!微信朋友圈删除了怎么恢复?

微信朋友圈是我们与朋友分享生活点滴的重要平台&#xff0c;但有时候微信出现异常&#xff0c;导致我们编辑好的朋友圈被删除了&#xff0c;这时候该怎么办呢&#xff1f; 幸运的是&#xff0c;微信提供了一种简单的方式来恢复已删除的朋友圈内容。微信朋友圈删除了怎么恢复&a…

react 学习笔记二:ref、状态、继承

基础知识 1、ref 创建变量时&#xff0c;需要运用到username React.createRef()&#xff0c;并将其绑定到对应的节点。在使用时需要获取当前的节点&#xff1b; 注意&#xff1a;vue直接使用里面的值&#xff0c;不需要再用this。 2、状态 组件描述某种显示情况的数据&#…

tkinter中是否有必要使用类

1. 问题背景 在使用tkinter编写事件驱动程序时&#xff0c;Fredrik Lundh的教程中提到&#xff0c;创建一个类&#xff08;App&#xff09;作为框架&#xff0c;并以类的实例运行程序&#xff0c;这样会更好&#xff0c;而不是直接启动程序。 以下是问题&#xff1a; 在tkin…

【Go语言快速上手(五)】文件操作协程操作

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; GO快速上手 1. 前言2. GO语言的文件操…

武汉星起航:挂牌上海股权中心,开启资本新篇章助力跨境电商飞跃

2023年10月30日&#xff0c;武汉星起航电子商务有限公司在上海股权托管交易中心成功挂牌展示&#xff0c;标志着这家在跨境电商领域拥有卓越声誉的企业正式迈入了资本市场的大门。对于武汉星起航来说&#xff0c;这不仅是其发展历程中的一个重要里程碑&#xff0c;更是对其业务…

Python学习笔记------异常

当检测到错误时&#xff0c;Python解释器就无法继续执行了&#xff0c;反而出现一些错误提示&#xff0c;就是所谓异常&#xff08;bug&#xff09; 1、异常的捕获方法 任何程序运行过程中都可能出现异常&#xff0c;我们可以在力所能及的范围内&#xff0c;对可能出现的bug提…

C语言趣味代码(四)

这一篇主要编写几个打字练习的小程序&#xff0c;然后通过这些小程序的实现来回顾复习我们之前学过的知识&#xff0c;然后通过这写打字练习的小程序来提升我们的打字技术和编程技术。 1. 打字练习 1.1 基本打字练习 1.1.1 基本实现 首先我们来制作一个用于计算并显示输入一…

ip网络广播前置放大器SV-7031 接纯后级功放

ip网络广播前置放大器SV-7031 接纯后级功放 感谢您使用我们的网络前置放大器SV-7031。 SV-7031具有1路AC200V OUT电源输出&#xff0c;1路AC200V IN电源输入&#xff1b;RJ45 网络接口&#xff0c;具有网络音频广播、本地广播功能。 18123651365 ip网络广播前置放大器SV-703…

vue-cli+vue3+vite+ts 搭建uniapp项目全过程(一)

unapp官方提供了cli 脚手架创建 uni-app 项目的文档 Vue3/Vite版要求 node 版本 18、20使用Vue3/Vite版创建不会提示选择模板&#xff0c;目前只支持创建默认模板 本文以vue3vitets为例 1、初始化项目 npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project 执行完生成…