Java学习——设计模式——结构型模式1

文章目录

  • 结构型模式
    • 代理模式
    • 适配器模式

结构型模式

结构型模式主要涉及如何组合各种对象以便获得更好、更灵活的结构。虽然面向对象的继承机制提供了最基本的子类扩展父类的功能,但结构型模式不仅仅简单地使用继承,而更多地通过组合与运行期的动态组合来实现更灵活的功能。

包括:
1、适配器
2、桥接
3、组合
4、装饰器
5、外观
6、享元
7、代理

代理模式

访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介

Java中的代理按照代理类生产时机不同又分为静态代理和动态代理。

静态代理类在编译期就生成,而动态代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种

结构
1、抽象主题类
2、真实主题类
3、代理类

静态代理

在这里插入图片描述

  • SellTickets
  • ProxyPoint
  • TrainStation
  • client
public class ProxyPoint implements SellTickets {

    private TrainStation station=new TrainStation();
    @Override
    public void sell() {
        System.out.println("代理点收取服务费用");
        station.sell();
    }
}

JDK动态代理
Java中提供了一个动态代理类Proxy,Proxy并不是上面的代理对象的类,而是提供了一个创建代理对象的静态方法来获取代理对象

  • SellTickets
  • ProxyFactory
  • TrainStation
  • client
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactory {
    private TrainStation station=new TrainStation();
    
    public SellTickets getproxyObject(){
        SellTickets sellTickets= (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),
                station.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理点收取服务费用");
                        Object result=method.invoke(station,args);
                        return result;
                    }
                });
        return sellTickets;
    }
}

ProxyFactory不是代理模式中所说的代理类,而代理类是程序在运行过程中动态的内存中生产的类。

CGLIB
如果没有定义SellTickets接口,只定义了TrainStation,JDK代理无法使用。

CGLIB是一个功能强大,高性能的代码生成包。为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。

CGLIB是第三方提供的包,需要引入jar包

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
  • ProxyFactory
  • TrainStation
  • client
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class ProxyFactory implements MethodInterceptor{
    private TrainStation target=new ProxyFactory();
    public TrainStation getProxyObject() {
        //创建Enhancer对象,类似于JDK代理中的Proxy类
        Enhancer enhancer = new Enhancer();
        //设置父类的字节码对象。指定父类
        enhancer.setSuperclass(TrainStation.class);
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        TrainStation proxyObject = (TrainStation) enhancer.create();
        return proxyObject;
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代售点收取一定的服务费用(CGLib代理)");
        //要调用目标对象的方法
        Object obj = method.invoke(station, objects);
        return obj;
    }
}

动态代理与静态代理相比,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,在接口方法数量比较多的时候,可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

代理模式优点:

  • 在客户端与目标对象之间起到一个中介作用和保护目标对象的作用
  • 代理对象可以扩展到目标对象的功能
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度

缺点:增加了系统的复杂度

适配器模式

将一个类的接口转换为客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作
适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少。

结构
1、目标接口
2、适配者类:被访问和适配的现存组件库中的组件接口
3、适配器类:是一个转换器,把适配者接口转换成目标接口

类适配器
在这里插入图片描述

public class SDAdapterTF extends TFCardImpl implements SDCard{

    @Override
    public String readSD() {
        System.out.println("adapter read tf card");
        return readTF();
    }

    @Override
    public void writeSD(String msg) {
        System.out.println("adapter write tf: "+msg);
        writeTF(msg);
    }
}

类适配器模式违背了合成复用原则。

类适配器是客户类有一个接口规范的情况下可用,反之不可用

对象适配器

在这里插入图片描述

public class SDAdapterTF implements SDCard {

    private TFCard tfCard;

    public SDAdapterTF(TFCard tfCard) {
        this.tfCard=tfCard;
    }

    @Override
    public String readSD() {
        System.out.println("adapter read tf card");
        return tfCard.readTF();
    }

    @Override
    public void writeSD(String msg) {
        System.out.println("adapter write tf: "+msg);
        tfCard.writeTF(msg);
    }
}

应用场景

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同

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

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

相关文章

uniapp多级动态表单规则

最近有个新的业务、主要涉及多层级的动态表单提交&#xff0c;其中又涉及很多类型&#xff0c;踩了很多坑之后&#xff0c;终于研发完毕。 传来的数据格式处理 传来的数据格式涉及比较多的内容&#xff0c;以下举例一个&#xff0c;涉及到规则的填写 规则写法有两种&#xff…

[足式机器人]Part4 南科大高等机器人控制课 CH12 Robotic Motion Control

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;CLEAR_LAB 笔者带更新-运动学 课程主讲教师&#xff1a; Prof. Wei Zhang 课程链接 &#xff1a; https://www.wzhanglab.site/teaching/mee-5114-advanced-control-for-robotics/ 南科大高等机器人控制课 Ch12 Robotic …

Android MVC 写法

前言 Model&#xff1a;负责数据逻辑 View&#xff1a;负责视图逻辑 Controller&#xff1a;负责业务逻辑 持有关系&#xff1a; 1、View 持有 Controller 2、Controller 持有 Model 3、Model 持有 View 辅助工具&#xff1a;ViewBinding 执行流程&#xff1a;View >…

【Python排序算法系列】—— 选择排序

​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 选择排序 过程演示&#xff1a; 选择排序实现代码&#xff1a; 分析选择排序&#xff1a…

Word 将页面方向更改为横向或纵向

文章目录 更改整个文档的方向更改部分页面的方向方法1&#xff1a;方法2&#xff1a; 参考链接 更改整个文档的方向 选择“布局”>“方向”&#xff0c;选择“纵向”或“横向”。 更改部分页面的方向 需要达到下图结果&#xff1a; 方法1&#xff1a; 选:中你要在横向页面…

6130 树的最长路

思路&#xff1a;树的最长路问题可以通过两次 DFS 求解&#xff0c;具体思路如下&#xff1a; 1.第一次 DFS 求树的直径 以任意一个点为起点进行深度优先遍历&#xff08;DFS&#xff09;&#xff0c;找到与该点距离最远的点 u 。 以 u 为起点进行 DFS &#xff0c;找到与 u 距…

计算机网络复习5

传输层——端到端 文章目录 传输层——端到端功能传输层的寻址与端口UDPTCPTCP连接管理TCP可靠传输TCP流量控制TCP拥塞控制网络拥塞的处理 功能 从通信和信息处理的角度看&#xff0c;传输层向它上面的应用层提供通信服务&#xff0c;它属于面向通信部分的最高层&#xff0c;同…

nodejs+vue+ElementUi农产品团购销售系统zto2c

目标是为了完成小区团购平台的设计和实现&#xff0c;在疫情当下的环境&#xff0c;方便小区业主购入生活所需&#xff0c;减小居民的生活压力 采用B/S模式架构系统&#xff0c;开发简单&#xff0c;只需要连接网络即可登录本系统&#xff0c;不需要安装任何客户端。开发工具采…

jmeter之beanshell使用:常用变量汇总

1.变量--日期 使用场景&#xff1a;当入参日期是变量&#xff0c;取当前日期 使用如下&#xff1a; &#xff08;1&#xff09;当前日期 import java.text.SimpleDateFormat; import java.util.Date;// 创建 SimpleDateFormat 对象并指定日期格式 SimpleDateFormat dateFor…

Seata AT TM->RC->RM一次完整的交互过程

原理 TM两阶段&#xff1a; 阶段1&#xff1a;TM向TC申请全局事务&#xff0c;netty客户端发起了一次记录xid的请求 阶段2&#xff1a;TC协调之后&#xff0c;决定执行RM是否提交或者回滚。 spring公共组件部分 1、SeataAutoConfiguration类 利用springboot自动装配机制从…

Ubuntu 安装MySQL以及基本使用

前言 MySQL是一个开源数据库管理系统&#xff0c;通常作为流行的LAMP&#xff08;Linux&#xff0c;Apache&#xff0c;MySQL&#xff0c;PHP / Python / Perl&#xff09;堆栈的一部分安装。它使用关系数据库和SQL&#xff08;结构化查询语言&#xff09;来管理其数据。 安装…

使用Vscode远程debug报错找不到Module找不到File

1..报第一个错 提示我无法导入自己写的module 如图&#xff1a; 解决办法&#xff1a; stackoverflow上说的在launch.json中加了一条 env&#xff0c;就解决了。 "env": { "PYTHONPATH":"/home/zt/ge-sc-master/ge-sc-master"}, 2.解决完第一个…

Mysql5.7主从数据库同步失败(日记文件错误)解决记录

记录一次Mysql主从数据库同步失败(日记文件错误)解决记录 查看同步状态&#xff1a; 具体错误&#xff1a; 检查mysql数据库日记 2021-06-10T03:45:43.522398Z 1 [ERROR] Error reading packet from server for channel : event read from binlog did not pass crc check; the…

【HarmonyOS开发】案例-记账本开发

OpenHarmony最近一段时间&#xff0c;简直火的一塌糊度&#xff0c;学习OpenHarmony相关的技术栈也有一段时间了&#xff0c;做个记账本小应用&#xff0c;将所学知识点融合记录一下。 1、记账本涉及知识点 基础组件&#xff08;Button、Select、Text、Span、Divider、Image&am…

简单了解SQL宽字节注入与httpXFF头注入(基于sqllabs演示)

1、宽字节注入 sqllabs-less-32为例 使用单引号进行测试 提示我们输入的单引号被转义符 \ 进行了转义&#xff0c;即转义符自动的出现在输入的特殊字符前面&#xff0c;这是防止sql注入的一种方法&#xff0c;导致无法产生报错。 这种情况我们就可以尝试宽字节注入&#xff…

报表控件FastReport VCL 中的新 S3 传输 (Amazon)

在本文中&#xff0c;我们将探讨新的 S3 传输。从功能上来说&#xff0c;S3 与大多数人习惯使用的有很大不同&#xff0c;因此在本文的开头&#xff0c;我们将详细介绍它的主要功能。 FastReport .NET 是适用于.NET Core 3&#xff0c;ASP.NET&#xff0c;MVC和Windows窗体的全…

数据结构--二叉搜索树的实现

目录 1.二叉搜索树的概念 2.二叉搜索树的操作 二叉搜索树的插入 中序遍历(常用于排序) 二叉搜索树的查找 二叉搜索树的删除 完整二叉树代码&#xff1a; 二叉搜索树的应用 key/value搜索模型整体代码 1.二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一…

亚信安慧AntDB数据并行加载工具的实现(一)

1.概述 数据加载速度是评判数据库性能的重要指标&#xff0c;能否提高数据加载速度&#xff0c;对文件数据进行并行解析&#xff0c;直接影响数据库运维管理效率。基于此&#xff0c;AntDB分布式数据库提供了两种数据加载方式&#xff1a; 一是类似于PostgreSQL的Copy命令&am…

ES6之解构赋值详解

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…

Nacos注册

一、简介 Nacos是阿里云开源的一个服务发现、配置管理和服务鉴权平台&#xff0c;它提供了一种更简单、更便捷、更开放的方式来管理服务&#xff0c;帮助开发者快速实现服务的发现、配置的管理、服务的鉴权等功能。Nacos可以帮助开发者轻松管理微服务应用中的服务提供者、服务…