设计模式の享元模板代理模式

文章目录

  • 前言
  • 一、享元模式
  • 二、模板方法模式
  • 三、代理模式
    • 3.1、静态代理
    • 3.2、JDK动态代理
    • 3.3、Cglib动态代理
    • 3.4、小结


前言

  本篇是关于设计模式中享元模式、模板模式、以及代理模式的学习笔记。


一、享元模式

  享元模式是一种结构型设计模式,目的是为了相似对象的复用,减少内存的消耗,在享元模式中,主要包含以下的角色:

  • Flyweight(抽象享元):定义享元对象的接口,规定了可以共享的内容。
  • ConcreteFlyweight(不可变对象):实现抽象享元接口,封装内部状态,确保可以被共享。
  • UnsharedConcreteFlyweight(可变对象):不需要共享的对象。
  • FlyweightFactory(享元工厂):管理和创建享元对象,确保可以复用已经存在的享元。
  • Client(客户端):使用享元对象,负责将外部状态传递给享元对象。

  下面通过一个案例说明一下,例如围棋,有黑白两种颜色的棋子,如果为每个棋子都创建一次对象,会占用很大的内存。如果利用享元模式进行改造,可以将下棋的行为看做是抽象享元,而棋子可以视为实现了抽象享元接口的不可变对象下棋的选手可以看作是可变对象

public interface PlayChess {/*** 下棋* @param player*/void playChess(Player player);}
/*** 棋子类*/
public class GochessPieces implements PlayChess{private String color;public GochessPieces() {}public GochessPieces(String color) {this.color = color;}@Overridepublic void playChess(Player player) {System.out.println(player + "落" + color);}
}
/*** 玩家*/
public class Player {private String name;public Player() {}public Player(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Player{" +"name='" + name + '\'' +'}';}
}
/*** 享元工厂*/
public class ChessFactory {private HashMap<String,PlayChess> map = new HashMap<>();public PlayChess getChess(String color){if (!map.containsKey(color)){map.put(color,new GochessPieces(color));}return (PlayChess)map.get(color);}public int poolSize(){return map.size();}
}

  模拟下棋的操作:

/*** 模拟下棋*/
public class Client {public static void main(String[] args) {ChessFactory chessFactory = new ChessFactory();PlayChess chess1 = chessFactory.getChess("白子");chess1.playChess(new Player("张三"));PlayChess chess2 = chessFactory.getChess("黑子");chess2.playChess(new Player("张三"));PlayChess chess3 = chessFactory.getChess("白子");chess3.playChess(new Player("李四"));PlayChess chess4 = chessFactory.getChess("黑子");chess4.playChess(new Player("李四"));PlayChess chess5 = chessFactory.getChess("白子");chess5.playChess(new Player("张三"));System.out.println("chessFactory.poolSize() = " + chessFactory.poolSize());}
}

Player{name=‘张三’}落白子
Player{name=‘张三’}落黑子
Player{name=‘李四’}落白子
Player{name=‘李四’}落黑子
Player{name=‘张三’}落白子
chessFactory.poolSize() = 2

  可以看出,虽然棋子被多次利用,但是在享元工厂中,最多只有两个棋子对象,即黑子白子,其关键点在于:

  • 共享对象:黑棋和白棋各只有一个实例,无需为每个棋子创建新对象。
  • 内外部状态分离:颜色作为内部状态是共享的;位置作为外部状态在调用时传入。
  • 减少内存占用:通过共享棋子对象,大幅减少了内存开销。

二、模板方法模式

  模板方法模式是一种行为设计模式,通过定义一个算法框架,允许子类在不改变算法结构的情况下重新定义算法的某些步骤。模板方法模式的主要目的是将算法的不变部分抽取到父类中,而将可变部分留给子类去实现,提高代码的复用性和灵活性,其中还涉及到钩子方法的使用。
  举一个生活中的案例,比如制作豆浆的过程,有相同的操作,也有针对不同类型的豆浆采取的特殊处理,用一个抽象的模板方法类,说明制作豆浆的步骤,以及对外提供制作的方法:

public abstract class CreateSoyaMilk {final void make(){prepare();if (isSoakBeans()){soakBeans();}grinding();boil();}/*** 钩子方法* @return*/boolean isSoakBeans(){return true;}/*** 准备材料* 不同的豆浆准备不同材料*/public abstract void prepare();/*** 浸泡豆子* 不同的豆浆浸泡不同的豆子*/public abstract void soakBeans();public void grinding(){System.out.println("打磨豆浆");}public void boil(){System.out.println("煮沸豆浆");}
}

  对于制作不同类型的豆浆,只需要继承模板方法类,然后根据自己的特点进行特殊处理即可:

public class RedBeanSoybeanMilk extends CreateSoyaMilk{@Overridepublic void prepare() {System.out.println("准备红豆");}@Overridepublic void soakBeans() {System.out.println("浸泡红豆");}
}

  如果黄豆豆浆不需要浸泡,则重写模板中的钩子方法

public class YellowBeanSoybeanMilk extends CreateSoyaMilk{@Overridepublic void prepare() {System.out.println("准备黄豆");}/*** 假设黄豆豆浆不需要浸泡*/@Overridepublic void soakBeans() {}@Overrideboolean isSoakBeans() {return false;}
}

  制作豆浆:

public class Client {public static void main(String[] args) {new RedBeanSoybeanMilk().make();System.out.println("**************************");new YellowBeanSoybeanMilk().make();}
}

准备红豆
浸泡红豆
打磨豆浆
煮沸豆浆


准备黄豆
打磨豆浆
煮沸豆浆

  模板方法模式也存在一定的局限性,因为是使用继承的体系结构,如果父类的修改影响较大,会导致所有子类需要同步更新。通常适用于有固定的算法结构,但子类的实现细节不同的场景。

三、代理模式

  代理模式是一种结构型设计模式,其核心目的是为了在使用目标对象的前后,对其进行拦截,增加一些统一的操作或是校验,是一种非常重要的模式,Spring AOP就是基于代理实现。
  代理模式可以分为静态代理动态代理,动态代理又可以细分为JDK动态代理Cglib动态代理。前者需要目标类实现接口,后者不需要,会在运行时动态生成目标类的子类。

3.1、静态代理

  首先演示一下什么是静态代理,静态代理要求目标类和代理类都要同时去实现接口:

public interface ITeacher {void teach();
}
public class TeacherDao implements ITeacher{@Overridepublic void teach() {System.out.println("开始上课。。。。");}
}
/*** 静态代理案例* 缺点,如果接口中要增加方法,被代理类和代理类都需要同步增加*/
public class TeacherDaoProxy implements ITeacher{private ITeacher teacher;public TeacherDaoProxy(ITeacher teacher){this.teacher = teacher;}@Overridepublic void teach() {System.out.println("课前准备。。。。");teacher.teach();System.out.println("下课。。。。。");}
}

课前准备。。。。
开始上课。。。。
下课。。。。。

3.2、JDK动态代理

  JDK动态代理的实现,主要依靠java.lang.reflect.Proxy包下的newProxyInstance方法,该方法会在运行时动态的生成代理类,详见:从源码角度分析JDK动态代理:

public interface ITeacher {void teach();
}
public class TeacherDao implements ITeacher {@Overridepublic void teach() {System.out.println("开始上课。。。。");}
}
public class JdkProxyFactory {/*** 被代理的目标类*/private Object target;public JdkProxyFactory(Object target) {this.target = target;}public Object getProxyInstance(){return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),(proxy, method, args) -> {System.out.println("课前准备");//通过反射调用目标方法Object o = method.invoke(target, args);System.out.println("下课");return o;});}
}
public class Client {public static void main(String[] args) {JdkProxyFactory jdkProxyFactory = new JdkProxyFactory(new TeacherDao());ITeacher proxyInstance = (ITeacher) jdkProxyFactory.getProxyInstance();proxyInstance.teach();}
}

3.3、Cglib动态代理

  JDK动态代理的实现,主要依靠org.springframework.cglib.proxy.MethodInterceptor包下的intercept方法,和JDK动态代理不同的是,不要求目标类实现接口,而是直接通过字节码技术生成目标类的子类

public class TeacherDao{public void teach() {System.out.println("开始上课。。。。");}
}
/*** cglib动态代理,不需要目标类实现接口* 运行时使用字节码技术动态增强*/
public class CglibProxyFactory implements MethodInterceptor {Object target;public CglibProxyFactory(Object target) {this.target = target;}public Object getProxyInstance(){Enhancer enhancer = new Enhancer();enhancer.setCallback(this);enhancer.setSuperclass(target.getClass());return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("课前准备");Object invoke = method.invoke(target, objects);System.out.println("下课");return invoke;}
}
public class Client {public static void main(String[] args) {CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(new TeacherDao());TeacherDao proxyInstance = (TeacherDao) cglibProxyFactory.getProxyInstance();proxyInstance.teach();}
}

  但是目标类,或方法如果被privatefinal关键字修饰,以及目标方法被static修饰,则无法进行代理,因为上述修饰符的方法无法被继承。

3.4、小结

  动态代理和静态代理的区别,主要体现在:

  • 静态代理是在编译期间由开发者显式编写代理类或通过工具生成,代理类在运行时已经存在:
    在这里插入图片描述
  • 动态代理在运行时动态生成代理类,代理类的字节码不会提前编写,而是通过反射或字节码操作框架生成。(使用JDK或第三方字节码库提供的API)
    运行时,JDK 动态代理会生成类似下面的代理类:com.light.proxy.jdkproxy.$Proxy0,其不会存在于target目录下。
      在Spring AOP中,也会根据是否实现了接口,去选择不同的动态代理。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux网络功能 - 服务和客户端程序CS架构和简单web服务示例

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 概述准备工作扫描服务端有那些开放端口创建客户端-服务器设置启动服务器和客户端进程双向发送数据保持服务器进程处于活动状态设置最小…

用人话讲计算机:Python篇!(十五)迭代器、生成器、装饰器

一、迭代器 &#xff08;1&#xff09;定义 标准解释&#xff1a;迭代器是 Python 中实现了迭代协议的对象&#xff0c;即提供__iter__()和 __next__()方法&#xff0c;任何实现了这两个方法的对象都可以被称为迭代器。 所谓__iter__()&#xff0c;即返回迭代器自身 所谓__…

小程序快速实现大模型聊天机器人

需求分析&#xff1a; 基于大模型&#xff0c;打造一个聊天机器人&#xff1b;使用开放API快速搭建&#xff0c;例如&#xff1a;讯飞星火&#xff1b;先实现UI展示&#xff0c;在接入API。 最终实现效果如下&#xff1a; 一.聊天机器人UI部分 1. 创建微信小程序&#xff0c…

【Android】unzip aar删除冲突classes再zip

# 解压JAR文件 jar xf your-library.jar # 解压AAR文件&#xff08;AAR实际上是ZIP格式&#xff09; unzip your-library.aar # 删除不需要的类 rm -rf path/to/com/example/unwanted/ # 对于JAR打包 jar cf your-library-modified.jar -C path/to/unzipped/ . # 对于AAR打包…

使用C语言编写UDP循环接收并打印消息的程序

使用C语言编写UDP循环接收并打印消息的程序 前提条件程序概述伪代码C语言实现编译和运行C改进之自由设定端口注意事项在本文中,我们将展示如何使用C语言编写一个简单的UDP服务器程序,该程序将循环接收来自指定端口的UDP消息,并将接收到的消息打印到控制台。我们将使用POSIX套…

你的第一个博客-第一弹

使用 Flask 开发博客 Flask 是一个轻量级的 Web 框架&#xff0c;适合小型应用和学习项目。我们将通过 Flask 开发一个简单的博客系统&#xff0c;支持用户注册、登录、发布文章等功能。 步骤&#xff1a; 安装 Flask 和其他必要库&#xff1a; 在开发博客之前&#xff0c;首…

Vue(二)

1.Vue生命周期 Vue生命周期就是一个Vue实例从 创建 到 销毁 的整个过程。生命周期四个阶段&#xff1a; 创建阶段&#xff1a;创建响应式数据。 挂载阶段&#xff1a;渲染模板。 更新阶段&#xff1a;修改数据&#xff0c;更新视图。 销毁阶段&#xff1a;销毁Vue实例。 …

macOS 配置 vscode 命令行启动

打开 vscode 使用 cmd shift p 组合快捷键&#xff0c;输入 install 点击 Install ‘code’ command in PATH Ref https://code.visualstudio.com/docs/setup/mac

python coding(二) Pandas 、PIL、cv2

Pandas 一个分析结构化数据的工具集。Pandas 以 NumPy 为基础&#xff08;实现数据存储和运算&#xff09;&#xff0c;提供了专门用于数据分析的类型、方法和函数&#xff0c;对数据分析和数据挖掘提供了很好的支持&#xff1b;同时 pandas 还可以跟数据可视化工具 matplotli…

期权VIX指数构建与择时应用

芝加哥期权交易 所CBOE的波动率指数VIX 是反映 S&P 500 指数未来 30 天预测期波动率的指标&#xff0c;由于预期波动率多用于表征市场情绪&#xff0c;因此 VIX 也被称为“ 恐慌指数”。 VIX指数计算 VIX 反映了市场情绪和投资者的风险偏好&#xff0c; 对于欧美市场而言…

一区牛顿-拉夫逊算法+分解+深度学习!VMD-NRBO-Transformer-GRU多变量时间序列光伏功率预测

一区牛顿-拉夫逊算法分解深度学习&#xff01;VMD-NRBO-Transformer-GRU多变量时间序列光伏功率预测 目录 一区牛顿-拉夫逊算法分解深度学习&#xff01;VMD-NRBO-Transformer-GRU多变量时间序列光伏功率预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.中科院一区…

Elasticsearch:什么是提示工程 - prompt engineering?

提示工程流程定义 提示工程是一种工程技术&#xff0c;用于设计生成式 AI 工具&#xff08;generative AI tools&#xff09;的输入&#xff0c;以调整大型语言模型并优化输出。 提示&#xff08;prompts&#xff09;被称为输入&#xff0c;而由生成性 AI 工具生成的答案是输…

html <a>设置发送邮件链接、打电话链接 <a href=“mailto:></a> <a href=“tel:></a>

1.代码 <ul><li>电话&#xff1a;<a href"tel:18888888888">188-8888-8888</a></li><li>邮箱&#xff1a;<a href"mailto:10000qq.com">10000qq.com</a></li><li>邮箱&#xff1a;<a hre…

前端关于pptxgen.js个人使用介绍

官方文档链接:Quick Start Guide | PptxGenJS git地址&#xff1a;https://github.com/gitbrent/PptxGenJS/ 1. 安装命令 npm install pptxgenjs --save yarn add pptxgenjs 2. 示例demo import pptxgen from "pptxgenjs"; // 引入pptxgen // 1. Create a Presenta…

【机器人】机械臂位置、轨迹和转矩控制概要

仍旧以 RRR&#xff08;三连杆&#xff09;为例&#xff0c;实现控制&#xff0c;可以采用以下步骤。这里的控制包括 位置控制轨迹控制 轨迹跟踪控制&#xff0c; 具体根据应用需求选择。以下是实现 RRR 机械臂控制的完整过程&#xff1a; 1. 定义机器人模型 通过 Denavit-H…

Python tkinter写的《电脑装配单》和 Html版 可打印 可导出 excel 文件

Python版 样图&#xff1a; 说明书&#xff1a; markdown # 电脑配置单使用说明书 ## 一、软件简介 电脑配置单是一个用于创建和比较两套电脑配置方案的工具软件。用户可以选择各种电脑配件,输入数量和价格,软件会自动计算总金额,并支持导出和打印配置单。 ## 二、主要功能 1. …

android studio更改应用图片,和应用名字。

更改应用图标&#xff0c;和名字 先打开AndroidManifest.xml文件。 更改图片文件名字&#xff08; 右键-->构建-->重命名&#xff08;R&#xff09;&#xff09;

Vue Web开发(十)

1. 用户管理新增&#xff0c;搜索&#xff0c;编辑&#xff0c;删除 本节课完成用户列表表单设计&#xff0c;使用table组件&#xff0c;同样模块化组件&#xff0c;CommonTable.vue组件&#xff0c;并且在User页面中引入&#xff0c;mock实现数据模拟&#xff0c;最终完成用户…

人工智能在VR展览中扮演什么角色?

人工智能&#xff08;AI&#xff09;在VR展览中扮演着多重关键角色&#xff0c;这些角色不仅增强了用户体验&#xff0c;还为展览的组织者提供了强大的工具。 接下来&#xff0c;由专业从事VR展览制作的圆桌3D云展厅平台为大家介绍AI在VR展览中的一些主要作用&#xff1a; 个性…

学工管理系统-职校信息化管理平台

学工管理系统是一种致力于提升职校管理效率和信息化水平的重要工具。它综合运用了现代信息技术和学工管理理念&#xff0c;为学校提供了全面、科学、高效的管理平台。 学工管理系统在学校管理中发挥着重要的作用。它能够实现学生信息的完整管理&#xff0c;包括学籍、课程、成绩…