设计模式⑦ :简单化

文章目录

  • 一、前言
  • 二、Facade 模式
    • 1. 介绍
    • 2. 应用
    • 3. 总结
  • 三、Mediator 模式
    • 1. 介绍
    • 2. 应用
    • 3. 总结

一、前言

有时候不想动脑子,就懒得看源码又不像浪费时间所以会看看书,但是又记不住,所以决定开始写"抄书"系列。本系列大部分内容都是来源于《 图解设计模式》(【日】结城浩 著)。该系列文章可随意转载。

二、Facade 模式

Facade 模式 :简单窗口

1. 介绍

一般来说,随着时间推移,程序会变得越来越复杂,这使得程序结构也变得越来越复杂,在使用这些功能时,我们需要先整理清楚他们之间的关系,注意正确的调用顺序。与其如此,不如为这个大型程序准备一个“窗口“,这样就无需关注每个类,只需要简单的对窗口提出请求即可。

使用 Facade 模式可以为互相关联在一起的错综复杂的类整理出高层接口。其中 Facade 角色可以让系统对外只有一个简单的接口。而且 Facade 角色还会考虑到系统内部各个类之间的责任关系和依赖关系,按照正确的顺序调用各个类。


Facade 模式 中出场的角色

  • Facade(窗口): 该角色是代表构成系统的许多其他角色的简单窗口。Facade 角色向系统外部提供高层接口
  • 构成系统的许多其他角色 :这些角色各自完成自己的工作,他们并不知道Facade 角色。Facade 角色调用其他角色进行工作,但是其他角色并不会调用 Facade角色。
  • Client(请求者):该角色负责调用 Facade 角色。

类图如下:

在这里插入图片描述


Demo如下:

// 基础数据获取
public class Database {/*** 防止外部创建*/private Database() {}/*** 获取基础数据* @return*/@SneakyThrowspublic static Properties getProperties() {Properties prop = new Properties();prop.setProperty("123456789@qq.com", "张三");prop.setProperty("987654321@qq.com", "李四");return prop;}
}// html 工具类
public class HtmlWriter {/*** 生成Html内容** @param title* @throws IOException*/public static String createContent(String title, String userName, String email) throws IOException {return "<html>" +"<head>" +"<title>" + title + "</title>" +"</head>" +"<body>" +"<h1>" + title + "</h1>" +"<div> 欢迎: " + userName + "</div>" +"<a href=\"" + email + "\"> " + email + "</a>" +"</html>";}/*** 生成html文件** @param fileName* @param content*/public static void writeHtml(String fileName, String content) {FileUtil.writeBytes(content.getBytes(StandardCharsets.UTF_8), fileName);}}// 页面生成类,
public class PageMaker {private PageMaker(){}/*** 构建欢迎页面*/public static void markWelcomePage(String mailaddr) throws IOException {final Properties prop = Database.getProperties();final String userName = prop.getProperty(mailaddr);final String content = HtmlWriter.createContent(userName, userName, mailaddr);HtmlWriter.writeHtml("D://welcome.html", content);}
}public class FacadeDemoMain {public static void main(String[] args) throws IOException {//调用 PageMaker#markWelcomePage 生成 html 页面PageMaker.markWelcomePage("123456789@qq.com");}
}

结果如下:生成welcome.html 文件,打开内容如图
在这里插入图片描述

对用户来说,只需要调用 PageMaker#markWelcomePage,传入指定邮箱便可以生成对应的 HTML页面,而其内部实现的HtmlWriter和Database对用户来说是无法感知的,即 PageMaker 对于 生成 Html 这个功能来说就是一个 Facade。

2. 应用

  • Dubbo 的分层模式个人认为也是Facade 模式的应用:Dubbo提供各个SPI 接口,如果用户需要扩展或改变功能只需要重新对应的SPI 即可。而无需关心 SPI 的上下游的关联和调用关系。如下图:
    在这里插入图片描述

  • Facade 模式在项目中几乎无时无刻不在用到,这里以 Spring 中随便找的一个方法为例:DispatcherServlet#doDispatch 中 会调用 HandlerExecutionChain#applyPreHandle 方法执行拦截器方法,那么这里就可以认为 HandlerExecutionChain 对 HandlerInterceptor 进行了分装。DispatcherServlet 只需要调用HandlerExecutionChain#applyPreHandle 便可以执行拦截器方法而无需关注具体实现。

在这里插入图片描述



个人使用:该部分内容是写给自己看的,帮助自身理解,因此就不交代项目背景了,读者请自行忽略(◐ˍ◑)

  • 个人理解在微服务级别,网关也起到类似 Facade 的作用:网关对外部暴露的接口是有限且可控的,外部无需关注网关内部接口的调用关系。

  • 在项目A 中,对同一数据的获取由于各个地区不同获取的途径或调用的第三方接口都不相同,此时需要在项目中对该数据的获取封装出一个 Facade ,当需要获取数据时只需要调用 Facade 暴露出的接口即可。Demo 如下:

    public interface DataSource {/*** 获取数据* @return*/String getData();
    }public class HttpDataSource implements DataSource {@Overridepublic String getData() {return "这是从 Http 调用获取的数据";}
    }public class DataBaseDataSource implements DataSource {@Overridepublic String getData() {return "这是从数据库获取的数据";}
    }public class DataFacade {private DataBaseDataSource dataBaseDataSource = new DataBaseDataSource();private HttpDataSource httpDataSource = new HttpDataSource();/*** 获取数据,nb 从数据库获取,sh通过http调用获取* @param region* @return*/public String getData(String region) {if ("nb".equals(region)) {return dataBaseDataSource.getData();} else if ("sh".equals(region)) {return httpDataSource.getData();} else {throw new RuntimeException("不支持");}}}public class DemoMain {public static void main(String[] args) {DataFacade dataFacade = new DataFacade();System.out.println(dataFacade.getData("nb"));System.out.println(dataFacade.getData("sh"));}
    }

    输出如下:

    在这里插入图片描述

3. 总结

扩展思路:

  • Facade 角色的工作:Facade 模式可以让复杂的东西看起来简单,使用 Facade 模式可以让我们不再在意后台工作的类和他们之间的关系。这里的重点是接口的变少了,这意味着程序和外部的关联关系弱化了,这使得我们的包作为组件更方便被复用。
  • 递归的使用Facade模式:在超大系统中往往包含非常多的包和类,如果我们在每个关键的地方都使用Facade 模式,系统的维护就会变的简单。

相关设计模式:

  • Abstract Factory 模式:可以将 Abstract Factory 模式看做是生成复杂实例时的 Facade 模式。因为它提供了“要想生成这个实例只需要调用这个方法就ok了”的简单接口。
  • Singleton 模式:有时会使用 Singleton 模式创建 Facade 角色。
  • Mediator 模式:在 Mediator 模式汇总, Mediator 角色与 Colleague 角色进行交互。而在 Facade 模式中,Facade 角色单方面地使用其他角色来对外提供高层接口。因此可以说 Mediator 是双向的,而 Facade 是单向的。

一时的小想法,仅仅个人理解,无需在意 :

  • Facade 模式不仅仅可以用于项目的代码中,在微服务搭建时,网关或者交换中心也起到类似的作用。对于外部访问,暴露出有限且可控的接口。
  • 个人认为最为简单的应用就是 MVC 中 Service 层暴露出的接口,每个 Service 接口内部需要调用多个 Dao 层的接口才能实现,那么就可以认为 Service 层是 Dao 层的封装。区别就是这里的 Service 层的“窗口”粒度更细。

三、Mediator 模式

Mediator 模式 : 只有一个仲裁者。

1. 介绍

当麻烦事发生时通知仲裁者,当发生涉及全体组员的事情,也通知仲裁者,当仲裁者下达指示时,组员会立即执行。组员之间不再相互沟通作出决定,而是发生任何事都向仲裁者报,一方面仲裁者站在整个团队的角度上对组员上报的事情做出决定。最后,整个团队的交流过程就变为了组员向仲裁者报告,仲裁者向组员下达指示。


Mediator 中出场的角色

  • Mediator(仲裁者、中介者):该角色负责定义与 Colleague 角色进行通信和做出决定的接口(API)
  • ConcreteMediator(具体的仲裁者、中介者):该角色负责实现 Mediator 角色的接口,负责作出实际决定。
  • Colleague(同事):该角色负责定义与 Mediator 角色进行通信的接口。
  • ConcreteColleague(具体的同事):该角色负责实现 Colleague 角色的接口。

类图如下:

在这里插入图片描述


2. 应用

  • Mediator 模式非常典型的应用则是在集群服务异常下线时的选举,如Redis的哨兵模式的监视和选举。
    以下面为例(内容来自于书籍 《Redis设计与实现》):

    1. 如下图展示了一个哨兵系统,server1 为主服务器,server2,server3, server4 为从服务器,sentinel 系统监视着这四个服务器
      在这里插入图片描述
    2. 假设这时server1 进入下线状态,那么从服务器 server2,server3, server4 对主服务器的复制将会被终中止,并且 Sentinel 系统会查询到 server1下线

    在这里插入图片描述
    3. 当 server1 的下线时长超过用户设定的下线时长上限时,Sentinel 系统就会对 server1 执行故障转移操作:

    1. Sentinel 系统会挑选 server1 的从服务器中的一个升级为主服务器
    2. 之后Sentinel 系统会想 server1 的所有从服务器发送新的复制指令,让他们成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕。
      另外,Sentinel 还会监视已经下线的 server1,当其重新上线时会将其设置为新的主服务器的从服务器。
      在这里插入图片描述


个人使用:该部分内容是写给自己看的,帮助自身理解,因此就不交代项目背景了,读者请自行忽略(◐ˍ◑)

  • Mediator 模式在目前的经验中似乎并没有用到,不过临时想到了一个应用场景:类如支付宝登录这种需要极度安全的操作肯定不能直接通过用户名密码验证,需要根据当前使用的手机是否新手机、当前账号多久没有登录、截止目前登录了多少次等种种因素决定当前登录是否有效,如此便可以使用仲裁者模式。Demo如下:

    // 判断接口
    public interface Colleague {/*** 信息判决* @param userInfo* @return*/int judgment(String userInfo);
    }public class LoginMadiator {// 登录次数验证private NumberColleague numberColleague = new NumberColleague();// 手机号验证private PhoneColleague phoneColleague = new PhoneColleague();/*** 登录判决** @return*/public boolean loginJudgment(String userInfo) {// 根据用户信息获取登录次数的判定final int numberScore = numberColleague.judgment(userInfo);// 根据用户信息获取是否新手机的的判定final int phoneScore = phoneColleague.judgment(userInfo);// 如果登录次数或是否新手机的判定有一个小于80分,本次登录验证不通过。return numberScore < 80 || phoneScore < 80;}
    }public class DemoMain {public static void main(String[] args) {String userName = "夏义春";String password = "123456789";LoginService loginService = new LoginService ();// 用户登录, 返回用户登录信息final String userInfo = loginService.login(userName, password);LoginMadiator loginMadiator = new LoginMadiator();// 如果本次登录裁决失败,则进行人脸或短信验证if (!loginMadiator.loginJudgment(userInfo)){// TODO : 进行人脸验证 或短信验证}}
    }
    

3. 总结

相关的设计模式:

  • Facade 模式:在 Mediator 模式汇总, Mediator 角色与 Colleague 角色进行交互。而在 Facade 模式中,Facade 角色单方面地使用其他角色来对外提供高层接口。因此可以说 Mediator 是双向的,而 Facade 是单向的
  • Observer 模式:有时会使用Observer 模式来实现 Mediator 角色与 Colleague 角色之间的通信。

一时的小想法,仅仅个人理解,无需在意 :

  • 一个仲裁类控制其他类来完成任务,也可以存在变种:即仲裁者也可以变成组员,类似 主从模式,可以自由选举。总的来说,需要抉择多重的任务级别适用于仲裁者模式。

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

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

相关文章

.NetCore Flurl.Http 4.0.0 以上管理客户端

参考原文地址&#xff1a;Managing Clients - Flurl 管理客户端 Flurl.Http 构建在堆栈之上System.Net.Http。如果您熟悉HttpClient&#xff0c;那么您可能听说过这个建议&#xff1a;不要为每个请求创建一个新客户端&#xff1b;重复使用它们&#xff0c;否则将面临后…

google网站流量怎么获取?

流量是一个综合性的指标&#xff0c;可以说做网站就是为了相关流量&#xff0c;一个网站流量都没有&#xff0c;那其实就跟摆饰品没什么区别 而想从谷歌这个搜索引擎里获取流量&#xff0c;一般都分为两种方式&#xff0c;一种是网站seo&#xff0c;另一种自然就是投广告&#…

软件测试阶段简介_单元测试、集成测试、配置项测试、系统测试

文章目录 前言一、软件测试“V”模型二、单元测试三、集成测试四、配置项测试五、系统测试总结 前言 一般来说&#xff0c;按照软件的研制阶段划分&#xff0c;软件测试可分为单元测试、集成测试、配置项测试、系统测试等。本文将对上述各测试阶段进行逐一介绍。 一、软件测试…

Halcon 一维测量

文章目录 算子矩形算子弧形算子移动到新的参考点 Halcon 案例测量保险丝的宽度&#xff08;边缘对测量&#xff09;使用助手进行测量 halcon 案例获取芯片引脚的个数平均宽度距离&#xff0c;连续两个边缘的距离&#xff08;measure_pos &#xff09;halcon 定位测量Halcon 测量…

HBase学习六:LSM树算法

1、简介 HBase是基于LSM树架构实现的,天生适合写多读少的应用场景。 LSM树本质上和B+树一样,是一种磁盘数据的索引结构。但和B+树不同的是,LSM树的索引对写入请求更友好。因为无论是何种写入请求,LSM树都会将写入操作处理为一次顺序写,而HDFS擅长的正是顺序写(且HDFS不…

【前后端的那些事】15min快速实现图片上传,预览功能(ElementPlus+Springboot)

文章目录 Element Plus SpringBoot实现图片上传&#xff0c;预览&#xff0c;删除效果展示 1. 后端代码1.1 controller1.2 service 2. 前端代码2.1 路由创建2.2 api接口2.2 文件创建 3. 前端上传组件封装 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&…

项目架构之Zabbix部署

1 项目架构 1.1 项目架构的组成 业务架构&#xff1a;客户端 → 防火墙 → 负载均衡&#xff08;四层、七层&#xff09; → web缓存/应用 → 业务逻辑&#xff08;动态应用&#xff09; → 数据缓存 → 数据持久层 运维架构&#xff1a;运维客户端 → 跳板机/堡垒机&#x…

ROS学习笔记5——话题通信自定义msg

在 ROS 通信协议中&#xff0c;数据载体是一个较为重要组成部分&#xff0c;ROS 中通过 std_msgs 封装了一些原生的数据类型&#xff0c;比如&#xff1a;String、Int32、Int64、Char、Bool、Empty.... 但是&#xff0c;这些数据一般只包含一个 data 字段&#xff0c;结构的单一…

[python]裁剪文件夹中所有pdf文档并按名称保存到指定的文件夹

最近在写论文的实验部分&#xff0c;由于latex需要pdf格式的文档&#xff0c;审稿专家需要对pdf图片进行裁剪放大&#xff0c;以保证图片质量。 原图&#xff1a; 裁剪后的图像&#xff1a; 代码粘贴如下。将input_folder和output_folder替换即可。(x1, y1)&#xff0c; (x2…

蓝桥杯备赛 day 2 —— 二分算法(C/C++,零基础,配图)

目录 &#x1f308;前言&#xff1a; &#x1f4c1; 二分的概念 &#x1f4c1; 整数二分 &#x1f4c1; 二分的模板 &#x1f4c1; 习题 &#x1f4c1; 总结 &#x1f308;前言&#xff1a; 这篇文章主要是准备蓝桥杯竞赛同学所写&#xff0c;为你更好准备蓝桥杯比赛涉及…

贪心算法 ——硬币兑换、区间调度、

硬币兑换&#xff1a; from book&#xff1a;挑战程序设计竞赛 思路&#xff1a;优先使用大面额兑换即可 package mainimport "fmt"func main() {results : []int{}//记录每一种数额的张数A : 620B : A//备份cnts : 0 //记录至少需要多少张nums : []int{1, 5, 10, 5…

Zookeeper简介

系列文章目录 Zookeeper安装教程 目录 一、Zookeeper简介 二、Zookeeper的数据结构 三、CPA理论 四、BASE 理论 五、ZooKeeper的特性 前言 这是我的学习笔记&#xff0c;以便后面翻阅。 一、Zookeeper简介 ZooKeeper是一个分布式的、开放源码的分布式应用程序协调服务&a…

element plus 可选择树形组件(el-tree) 怎样一键展开/收起?实现方法详解

实现代码&#xff1a; 按钮&#xff1a; <el-button click"takeall" style"height: 24px">{{zhanstatus % 2 ! 0 ? "收起所有" : "展开所有"}} </el-button> 组件&#xff1a; <el-form-item label"可选择菜单…

GIS复试Tips(特别是南师大)

注&#xff1a;本文仅个人观点&#xff0c;仅供参考 在这提前㊗️24年考南师大GISer成功上岸&#xff01; 当然&#xff0c;考研是个考试&#xff0c;总有人顺利上岸&#xff0c;稳上岸或逆袭上岸&#xff0c;但可能也有人被刷&#xff0c;这是常态。 所以&#xff0c;㊗️你…

如何服务器用守护进程保证程序稳定运行

如何服务器用守护进程保证程序稳定运行 一、前言 平常在使用服务器的时候&#xff0c;服务一直不稳定&#xff0c;遂从nohup改为创建一个systemd服务来管理Python程序。 要求&#xff1a;有root权限 二、步骤 1、创建systemd服务文件 创建一个新的systemd服务文件&#xf…

X-Bogus加密参数分析与jsvmp算法(仅供学习)

文章目录 1. 抓包分析2. X-Bogus参数分析 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋友可以关注《爬虫…

day20 最大的二叉树 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树

题目1&#xff1a;654 最大二叉树 题目链接&#xff1a;654 最大二叉树 题意 根据不重复的整数数组nums构建最大的二叉树 &#xff0c;根节点是数组中的最大值&#xff0c;最大值左边的子数组构建左子树&#xff0c;最大值右边的子数组构建右子树 nums数组中最少含有1个元素…

怿星科技测试实验室获CNAS实验室认可,汽车以太网检测能力达国际标准

2023年12月27日&#xff0c;上海怿星电子科技有限公司测试实验室&#xff08;下称&#xff1a;EPT LABS&#xff09;通过CNAS实验室认可批准&#xff0c;并于2024年1月5日正式取得CNAS实验室认可证书&#xff08;注册号CNAS L19826&#xff09;&#xff0c;标志着怿星科技的实验…

48-DOM节点,innerHTML,innerText,outerHTML,outerText,静态获取,单机click,cssText

1.DOM基础 Document Object Module,文档对象模型,window对象,document文档,都可以获取和操作 1)文档节点 2)属性节点(标签内的属性href,src) 3)文本节点(标签内的文字) 4)注释节点 5)元素节点(标签) 2.获取元素节点 2.1通过标签名获取getElementsByTagName() …

运维平台介绍:视频智能运维平台的视频质量诊断分析和告警中心

目 录 一、视频智能运维平台介绍 &#xff08;一&#xff09;平台概述 &#xff08;二&#xff09;结构图 &#xff08;三&#xff09;功能介绍 1、运维监控 2、视频诊断 3、巡检管理 4、告警管理 5、资产管理 6、工单管理 7、运维…