恭喜胡歌喜提小棉袄一件,彭于晏表示压力很大

简介: 恭喜胡歌喜提小棉袄一件,彭于晏表示压力很大

设计模式系列 - 连载3

当年胡歌放话说:

“彭于晏都没结婚,他不急,我也不急。”

结果今天突然官宣当爹

喜提宝贝女儿

今天,大概小彭同学

是不是可以急一急了?

遥想5年后

小胡妹妹都可以上街

替爸比打酱油了

正好我们可以讲一讲小代理的故事

结构型模式

前面两章

主要是介绍创建型模式

今天开始介绍结构型

主要分为7种

分别是:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

他们的共同特点是,通过组合,让简单的类组成更大、更复杂的结构

首先介绍我最喜欢用的:代理模式

代理模式

代理的核心是

对象直接不直接调用

而是有一个代理者作为中介

形式上满足调用的规则

很多人读书时

不敢和喜欢的同学表白

而是让其他同学传话

这个传声筒,就是代理

常见的代理

生活中的代理很多

房产中介、快递小哥、代办年检……

这些共同特点是,某人需要一项服务

但他自己不方便、不会、不擅长

所以需要一个代理来做

还有另一种

比如:传达室大爷、总裁的秘书……

某人需要接触到对方

但对方不让你接触

只能间接进行联系

写一个最简单的代理类

写一个发短信的例子

public class SmsMessageProxy{
    /**
     * 电信的短信服务
     */
    private ChinaTelecomSmsService service;
    /**
     * 服务访问令牌
     */
    private String access_token="JSHDQ-EKQKH-KKAOW-9WWJE"; 
    public void send(String mobile, String content){
        service.send(access_token, new Date(),mobile, content);
    }
}
public class BizController{
    private SmsMessageProxy smsMessageProxy;
    public DTO finish(Param param){
        // ...
        smsMessageProxy.send(param.getMobile(), "您的业务已办结");
        return DTO.success();
    }
}

这就是一个简单的例子

有3个类

  1. BizController
  2. SmsMessageProxy
  3. ChinaTelecomSmsService

1 作为业务的执行者,无法和 3 直接通讯

而是间接使用了 2 这个代理类

通过间接调用,形式上完成了 1~3 的调用

我们可以发现

代理类除了转发请求之外

还额外做了令牌传参,日期传参工作

其实是简化了调用的参数

给他们提供了默认值

这样做对使用方是有利的

代理的应用场景

试想一下

我有没有这方面的需要

比如监控,比如统计,还有事务、日志、权限等等

这些其实都可以用代理proxy来实现

主要解决一些非功能性的需求开发

以日志为例

核心功能类只需瞒住功能性的需求

然后用代理进行包装

将日志写在代理类中

这样的话,直接调用核心类是没有日志的

当需要日志时,采用代理转发的方式实现。

静态代理

上面的示范是最简单的代理

一个目标类 target

一个代理类 proxy

他们彼此对应

因此有人经常将两者共同抽象出一套接口

这种代理方式可以解决常规的一些问题

比如:

/**
 * 短信服务接口
 */
public interface SmsService{
    void send(String mobile, String content);
}
/**
 * 电信短信服务
 */
public class TelecomSmsService implements SmsService{
    public void send(String mobile, String content){
        // TODO 发送电信短信
    }
}
/**
 * 代理类
 */
public class SmsProxy implements SmsService{
    private SmsService service;
    public void send(String mobile, String content){
        // TODO 设置请求 header 等鉴权信息
        service.send(mobile, content);
        // TODO 记录发送日志
    }
}
/**
 * 测试类
 */
public class ProxyTest{
    @Test
    void test(){
        SmsProxy proxy=new SmsProxy();
        proxy.send("13812345678", "我爱你");
    }
}

这就是简单的实现

在Spring的AOP里

就大量的使用了代理模式

大家如果经常看日志

就会对proxy这个词不陌生

静态代理存在的问题

前面这个例子能解决简单问题

但随着类的内容越来越多

每次 target 类发生变化,或者增加子类

proxy 都有可能需要同步调整

这加大了维护的代价

因此我们希望有一种尽量少改代码的方法

动态代理

动态代理的核心是反射 reflect

他能解决,一个类,对另外一堆相似的类的统一代理问题

还是前面的例子,我们有一个电信短信类

但后面可能会扩充 移动 和 联通

如果想少改代码

应该怎么做呢?

来看一个示范

/**
 * 短信服务接口
 */
public interface SmsService{
    void send(String mobile, String content);
}
/**
 * 电信短信服务
 */
public class TelecomSmsService implements SmsService{
    public void send(String mobile, String content){
        // TODO 发送电信短信
    }
}
// 以上两个类和前面一样,下面是新增的类
/**
 * 联通短信服务
 */
public class UnicomSmsService implements SmsService{
    public void send(String mobile, String content){
        // TODO 发送联通短信
    }
}
/**
 * 微信服务,接口和前面的不一样,但方法名类似
 */
public class WechatService implements NetService{
    public void send(String appid, String openid, String content){
        // TODO 发送微信公众号消息
    }
}

现在问题变复杂了

不但有多个平行子类

还有个完全搭不上关系的微信消息类

此时代理怎么做呢?


Java里有一个代理公共接口 InvocationHandler

他的用法我们举一个例子

public class MessageProxy implements InvocationHandler {
    private Object bean;
    public MessageProxy(Object bean) {
        this.bean=bean;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object re=null;
        String methodname=method.getName();
        if (methodname.equals("send")){
            // TODO 设置请求 header 等鉴权信息
            re = method.invoke(bean, args);
            // TODO 记录发送日志
        }
        return re;
    }
}
/**
 * 测试类
 */
public class ProxyTest{
    @Test
    void test(){
  MessageProxy proxy=new MessageProxy(new TelecomSmsService());
  SmsService service0=(SmsService)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] {SmsService.class}, proxy);
  service0.send("13812345678", "我爱你");
  MessageProxy proxy1=new MessageProxy(new UnicomSmsService());
  SmsService service1=(SmsService)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] {SmsService.class}, proxy);
  service0.send("13812345678", "我爱你");
  MessageProxy proxy2=new MessageProxy(new WechatService());
  NetService service2=(NetService)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] {SmsService.class}, proxy);
  service0.send("wx81283123", "oejak8123123", "我爱你");
    }
}

可以发现

动态代理类能够适用变化的问题

当目标类发生变化

代理类可以不变

甚至可以一个代理管多个目标类

这就是通过反射来实现的

总结

代理模式是一种常用的设计模式

解决类之间的线性调用问题

通过代理

可以使非功能需求得到很好的解决

相关文章
|
数据采集 运维 监控
|
算法 Java C++
27.【C/C++ 最全vector数组的用法 (详解)】(一)
27.【C/C++ 最全vector数组的用法 (详解)】
970 0
|
人工智能
AI 绘画Stable Diffusion 研究(十二)SD数字人制作工具SadTlaker插件安装教程
AI 绘画Stable Diffusion 研究(十二)SD数字人制作工具SadTlaker插件安装教程
2007 0
|
10月前
|
人工智能 监控 Cloud Native
云原生AI赋能文旅数智化转型:玄晶引擎AI数字员工落地长白山康养项目全解析
本文以长白山大健康企业为例,介绍其通过玄晶引擎云原生AI数字员工实现“养生+文旅”模式智能化升级的实践。涵盖技术架构、运营适配、营销创新与落地经验,展现AI在内容生产、客服转化、B端获客等环节的全链路赋能,助力企业收益率提升47%、团队扩张35%,为文旅产业数智化转型提供可复用范本。
600 13
|
7月前
|
SQL 安全 关系型数据库
postgressql提示sorry, too many clients的解决办法
本地测试PgSQL集群时频现“too many clients”错误,主因是应用端连接池(各设100)叠加超出了PostgreSQL的max_connections限制(默认100)。PgSQL不会自动回收空闲连接,需靠连接池或超时机制管理。附实用命令:SHOW max_connections;SELECT count(*) FROM pg_stat_activity;SHOW port;及OS级ulimit和端口范围检查。
454 3
|
7月前
|
Linux API iOS开发
从零到精通!OpenClaw(Clawdbot)阿里云/本地部署、API配置与常见问题一站式手册(2026最新版)
2026年,OpenClaw(原Clawdbot、Moltbot)作为开源AI智能体领域的标杆框架,凭借“本地优先、隐私安全、插件扩展、多端适配”的核心特性,成为个人提升效率、企业简化协作的首选工具。它并非传统意义上的聊天机器人,而是能将自然语言指令转化为实际操作的“数字员工”,可实现文件管理、网页自动化、代码辅助、信息检索等全场景任务,适配阿里云云端部署与MacOS、Linux、Windows11本地部署,且能无缝对接阿里云百炼Coding Plan免费大模型,零成本实现智能升级。
906 4
|
10月前
|
小程序 安全 NoSQL
陪玩小程序/代练APP/代打一键发布任务/打手抢单方便快捷
本文介绍游戏陪玩与代练平台搭建方案,涵盖业务定位、源码采购、部署环境及合规要求。建议明确“陪玩社交”或“技术代练”主方向,选择正规渠道获取商业源码,部署4核8G服务器,配置Nginx、MySQL、Redis环境,办理ICP证。运营需集成官方支付、押金托管、内容审核及打手实名认证机制,确保安全合规。
726 0
|
XML 小程序 前端开发
小程序制作教程
小程序制作教程
2019 3
小程序制作教程
|
存储 网络架构
什么是路由器?
路由器可以连接两个或更多网段。这些是在其路由表中存储信息的智能网络设备,例如路径,跳数等。有了这个信息,他们就可以确定数据传输的最佳路径。路由器在 OSI 网络层运行。
|
JavaScript 开发者 Docker
Docker容器化实战:构建并部署一个简单的Web应用
Docker容器化实战:构建并部署一个简单的Web应用