12.从项目经理的生存哲学到适配器模式(Adapter Pattern)

news2024/11/18 5:57:38

如果这个世界没有了项目经理,事情的发展可能并不会如同想象中一样美好,相反,对于开发人员来说可能是噩梦的开始。
比如:
客户因为几个需求的具体实现大发雷霆,甚至开始恶语相向,一通含ma量极高的“斯伯坦语”下来,瞬间让性情耿直的开发人员集体开团,场面一度难以控制。因为对于大多数技术部门的人员来说,这种过度“世俗”的沟通方式并不能被接受。
但如果此时有一个经验丰富的项目经理作为缓冲夹在中间,将客户的“斯伯坦语”过滤处理成纯粹的需求,传达给技术人员,再将技术人员的解决方案加以“怀柔的”修饰传递给客户。世界是不是就变得美好了呢?
语言是门艺术,沟通充满了技巧。


一言

适配器模式即:将某个类的接口转换成客户端期望的另一个接口表示,让原本不匹配的两个对象可以协同工作。


概述

在刚刚的例子中,项目经理实际上就是充当了适配器的角色,让原本水火不容的客户和技术人员能够携起手来,共同完成项目。其核心在于适配器的兼容性。
在软件设计领域,通常将适配器模式划分为结构型模式的一种。从用户的角度来看,是看不到被适配者的,就比如客户通常不会关心技术人员的存在,从这个角度来说,整体的结构的耦合度是很低的。用户调用适配器,适配器再调用被适配者。
在适配器的具体实现上,通常有:类适配器、对象适配器、接口适配器三种。


类适配器

项目经理: 客户就是我的爸爸!

在这里插入图片描述

参照我们此前描述的情景,项目经理(适配器类)需要将客户类(被适配对象)当作父亲,通过继承获得客户的初始需求,同时还要掌握一定管理能力(实现管理接口),通过管理能力将客户的需求进行处理,交付给开发人员。

图解

在这里插入图片描述

实例

我们假定客户的每一个需求都带有一个愤怒值,当这个愤怒值高于10时,开发人员将认位自己受到了冒犯并拒绝工作,而项目经理则需要即时的将客户的需求通过处理交付给开发人员,以期工作的正常开展。
客户

public class Customer {
    public int communicate(){
        int anger = 10000;
        System.out.println("沟通需求,愤怒指数:"+anger);
        return anger;
    }
}

管理能力

public interface Manage {
    public int skill();
}

项目经理

public class ProjectManager extends Customer implements Manage{
    @Override
    public int skill() {
        int anger = communicate();
        return anger/1000;
    }
}

开发人员

public class Devops {
    public void work(Manage manage){
        if (manage.skill()>10)
            System.out.println("你的态度让我无法工作");
        else
            System.out.println("沟通方式很尊重我,工作包在我身上");
    }
}

分析

Java是单继承机制,所以类适配器需要继承客户类这一点算是一个缺点,因为这要求管理能力必须是接口,有一定局限性;
客户类的方法在Adapter(项目经理)中都会暴露出来,也增加了使用的成本。由于其继承了客户类,所以它可以根据需求重写客户类的方法,使得Adapter的灵活性增强了。


对象适配器

项目经理:客户不是我的爸爸,他是我的家人。我们彼此尊重、方向一致。

在这里插入图片描述

实际上我们已经清楚的看到了类适配器存在的问题:项目经理的膝盖太软了,一直把客户(被适配对象)当作自己的父亲,这使得整个结构存在着很大的局限性。
对象适配的思路上就是让项目经理站起来,不是直接继承客户,而是通过持有客户的对象来解决兼容问题。

图解

在这里插入图片描述

实例核心

public class ProjectManager implements Manage {
    private Customer customer;

    public ProjectManager(Customer customer){
        this.customer = customer;
    }

    @Override
    public int skill() {
        int anger = customer.communicate();
        return anger/1000;
    }
}

分析

对象适配器和类适配器其实算是同一种思想,只不过实现方式不同根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承被适配对象的局限性问题,也不再要求适配能力必须是接口。
使用成本更低,结构上也更灵活。


接口适配器

有很多资料也将这种方式称为“缺省适配器模式”,顾名思义,当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现 (空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
这其实非常适用于一个接口不想使用其所有方法的情况。
在这里插入图片描述
这种方式很容易理解,这里不过多赘述。


适配器模式在SpringMVC源码的应用

相信有的朋友看到SpringMVC再结合我们上文讲到的适配器模式(Adapter)就已经恍然大悟了。SpringMVC框架中一个非常重要的角色就是HandlerAdapter。
我们可以回想一下SpringMVC的工作过程(这里不做展开,忘记了的同学可以查阅下相关资料),其中有一个重要环节就是DispatchServlet 会根据 收到的Handler 选择一个合适的HandlerAdapter。这里就是适配器模式的关键应用。
下面我将相关源码主体剥离了一部分出来,大家可以体会下。

部分源码

Controller

public interface Controller {
}
class HttpController implements Controller {
    public void doHttpHandler() {
        System.out.println("http...");
    }
}

class SimpleController implements Controller {
    public void doSimplerHandler() {
        System.out.println("simple...");
    }
}

class AnnotationController implements Controller {
    public void doAnnotationHandler() {
        System.out.println("annotation...");
    }
}

HandlerAdapter

public interface HandlerAdapter {
    public boolean supports(Object handler);
    public void handle(Object handler);
}

class SimpleHandlerAdapter implements HandlerAdapter {
    public void handle(Object handler) {
        ((SimpleController) handler).doSimplerHandler();
    }

    public boolean supports(Object handler) {
        return (handler instanceof SimpleController);
    }
}

class HttpHandlerAdapter implements HandlerAdapter {
    public void handle(Object handler) {
        ((HttpController) handler).doHttpHandler();
    }

    public boolean supports(Object handler) {
        return (handler instanceof HttpController);
    }
}

class AnnotationHandlerAdapter implements HandlerAdapter {
    public void handle(Object handler) {
        ((AnnotationController) handler).doAnnotationHandler();
    }

    public boolean supports(Object handler) {
        return (handler instanceof AnnotationController);
    }
}

DispatchServlet

public class DispatchServlet {
    public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

    public DispatchServlet() {
        handlerAdapters.add(new AnnotationHandlerAdapter());
        handlerAdapters.add(new HttpHandlerAdapter());
        handlerAdapters.add(new SimpleHandlerAdapter());
    }

    public void doDispatch() {
        HttpController controller = new HttpController();
        // AnnotationController controller = new AnnotationController();
        //SimpleController controller = new SimpleController();
        HandlerAdapter adapter = getHandler(controller);
        adapter.handle(controller);
    }

    public HandlerAdapter getHandler(Controller controller) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(controller)) {
                return adapter;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        new DispatchServlet().doDispatch(); // http...
    }
}

图解

在这里插入图片描述

分析

对于多种Controller,应该有对应的适配器对其做处理。
在DispatchServlet从request中取到handler对象后,适配器可以得到自己希望的Controller进而通过getHandler方法得到对应的适配器,在通过适配器执行handle,也就能执行对应controller的对应方法了。


好啦,希望通过此文能让大家对适配器模式有更深一步的认识,也期待获得大家的指正或共鸣。
关注我,共同进步,每周至少一更。——Wayne

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【EEG信号处理】ERP相关

ERP&#xff0c;全称为event-related potential&#xff0c;中文是事件相关电位。 首先要明确的一点是&#xff0c;ERP是根据脑电图EEG得到的&#xff0c;他是EEG的一部分&#xff0c;是最常用的时域分析方法 可能有一部分是介绍不到的&#xff0c;望谅解 在维基百科中给的定义…

Vue3的v-model

目录 基本用法 底层机制 v-model 的参数 多个 v-model 绑定 处理 v-model 修饰符 带参数的 v-model 修饰符 例子 总结&#xff1a;Vue 3 中的 v-model 指令与 Vue 2 中的 v-model 相比有一些变化和改进。最显著的变化是&#xff0c;在 Vue 3 中&#xff0c;v-model 可以…

matlab appdesigner系列-仪器仪表4-开关、开关(切换)、开关(翘板)

开关、开关&#xff08;切换&#xff09;、开关&#xff08;翘板&#xff09;&#xff0c;可进行On和Off两种状态切换 示例&#xff1a;开关开启时&#xff0c;可通过滑块调整表盘数值&#xff0c;并有提示框提示 开关关闭时&#xff0c;滑块、表盘数值清零&#xff0c;并有提…

【DDD】学习笔记-理解上下文映射

一个软件系统通常被分为多个限界上下文&#xff0c;这是运用“分而治之”思想来降低业务复杂度的有效手段&#xff0c;设计的难题往往会停留在“如何分”&#xff0c;然而限界上下文之间的“怎么合”问题同样值得关注&#xff0c;分与合遵循的还是软件设计的最高原则——高内聚…

系列五十、idea父子项目忽略部分文件

一、idea父子项目忽略部分文件 **/mvnw **/mvnw.cmd **/.mvn **/target/ .idea **/.gitignore

一进一出模拟量信号隔离变送器

一进一出模拟量信号隔离变送器 捷晟达科技推出一进一出模拟量信号隔离变送器 深圳捷晟达科技推出一款具有隔离,放大,转换保护功能的一进一出的小型隔离变送器设备,该设备可以把模拟量(4-20mA/0-10V等)标准信号转换用户需要的信号,该产品具有抗EMC干扰,可以有效的保护后级设备安…

【MySQL】双写、重做日志对宕机时脏页数据落盘的作用的疑问及浅析

众所周知&#xff0c;双写机制、重做日志文件是mysql的InnoDB引擎的几个重要特性之二。其中两者的作用都是什么&#xff0c;很多文章都有分析&#xff0c;如&#xff0c;双写机制&#xff08;Double Write&#xff09;是mysql在crash后恢复的机制&#xff0c;而重做日志文件&am…

网安文件包含漏洞

文件包含概念&#xff1a; 开发人员通常会把可重复使用的函数写到单个文件中&#xff0c;在使用某些函数时&#xff0c;直接调用此文件&#xff0c;而无需再次编写&#xff0c;这种调用文件的过程一般被称为包含。为了使代码更加灵活&#xff0c;通常会将被包含的文件设置为变…

docker+jekins+maven+ssh 持续集成交付部署 jar包

一. docker环境搭建&#xff0c;此处略过。 二. docker部署jekins 2.1 拉取镜像&#xff0c;挂载工作目录,xxxx为宿主机指定工作目录 docker pull jenkins/jenkins docker run -d -p 8080:8080 -p 50000:50000 --name jenkins --privilegedtrue -v xxxxxxxxxx:/var/jenkins…

源码安装nginx并提供服务脚本

一、下载nginx ①官网复制下载链接 ②在Linux中下载 [rootopenEuler2 ~]# wget -c https://nginx.org/download/nginx-1.24.0.tar.gz 二、解压并指定路径 [rootopenEuler2 ~]# tar xf nginx-1.24.0.tar.gz -C /usr/local/src/ 三、安装依赖 dnf install -y gcc gcc-c mak…

使用plotly dash 画3d圆柱(Python)

plotly3D &#xff08;3d charts in Python&#xff09;可以画3维图形 在做圆柱的3D装箱项目&#xff0c;需要装箱的可视化&#xff0c;但是Mesh &#xff08;3d mesh plots in Python&#xff09;只能画三角形&#xff0c;所以需要用多个三角形拼成一个圆柱&#xff08;想做立…

vue实现跳转传参查询

vue实现跳转传参查询&#xff1a; 应用场景&#xff1a;外部链接携参跳转目标页时,避免多次输入查询信息查询 目标需求&#xff1a;登录及非登录状态均可跳转自动查询 避坑指南&#xff1a;token失效时需要重新缓存及路由导航缓存判断 简单实现&#xff1a;缓存信息&#xff0c…

PeakCAN连接到WSL2 Debian

操作步骤 按照以下步骤进行操作&#xff1a; 在Windows下安装PeakCAN驱动并安装&#xff0c;地址是https://www.peak-system.com/PCAN-USB.199.0.html?&L1 在Windows下安装usbipd&#xff0c;地址是https://github.com/dorssel/usbipd-win/releases&#xff0c;最新版是…

Elasticsearch:如何为 Elastic Stack 配置 AI Assistant

了解并安装 Elastic AI Assistant Elastic 推出了 Observability AI Assistant&#xff0c;这是一款利用生成式 AI 来增强你的 Observability 体验的强大工具。 该 AI 助手由 OpenAI 或 Azure OpenAI 服务的连接器提供支持&#xff0c;可带来上下文洞察和聊天功能&#xff0c;…

vue中的vuex

在Windows的应用程序开发中&#xff0c;我们习惯了变量&#xff08;对象&#xff09;声明和使用方式&#xff0c;就是有全局和局部之分&#xff0c;定义好了全局变量&#xff08;对象&#xff09;以后在其他窗体中就可以使用&#xff0c;但是窗体之间的变量&#xff08;对象&am…

c++学习记录 多态—案例2—电脑组装

#include<iostream> using namespace std;//抽象不同的零件//抽象的cpu类 class Cpu { public://抽象的计算函数virtual void calculate() 0; };//抽象的显卡类 class VideoCard { public://抽象的显示函数virtual void display() 0; };//抽象的内存条类 class Memory …

【MySQL】聚合函数和内置函数

文章目录 1 :peach:聚合函数:peach:2 :peach:group by子句的使用:peach:3 :peach:内置函数:peach:3.1 :apple:日期函数:apple:3.2 :apple:字符串函数:apple:3.3 :apple:数学函数:apple: 4 :peach:其它函数:peach: 1 &#x1f351;聚合函数&#x1f351; 函数说明COUNT([DISTIN…

【大数据】Flink 架构(三):事件时间处理

《Flink 架构》系列&#xff08;已完结&#xff09;&#xff0c;共包含以下 6 篇文章&#xff1a; Flink 架构&#xff08;一&#xff09;&#xff1a;系统架构Flink 架构&#xff08;二&#xff09;&#xff1a;数据传输Flink 架构&#xff08;三&#xff09;&#xff1a;事件…

(十四)测频NE555应用

文章目录 NE555简介NE555原理图如何对NET_SIG&#xff08;P34&#xff09;引脚计脉冲测频应用部分代码现象 NE555简介 NE555是一种集成电路&#xff0c;其内部结构包括比较器、RS触发器、电压比较器和输出级三个主要功能模块。是由硬件直接产生的脉冲 NE555一些的常见应用&am…

Orion-14B-Chat-Plugin本地部署的解决方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…