你用过哪些设计模式(一)?
什么是设计模式?
一些经验总结的最佳实践!
是不是必须要用?
并不是,但是既然已经说是最佳实践了,该用的地方,你不用,就有些违背常理了。
一、单例
这个或许是最最最常见,也是最最最常用的了。
为什么要用单例模式?
因为只需要一个对象就够了(有时候只能有一个,有时候是不需要有多个)。
对象的创建和销毁也是成本。
1、Kafka 消息发送
比如,你要发 kafka 消息,你要创建一个 Producer 对象,因为是 Producer 线程安全的,所以一般创建一个对象就够了。
借用官方的一个建议:
2、Spring 容器 bean
Spring 容器管理的对象默认创建模式为单例。当然你也可以根据实际业务对不同的对象设置不同的创建模式。
singleton: (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
需要说明的是,这个单例只是针对一个容器。
3、本地缓存
使用 Guava 本地缓存来加速业务响应。这个对于一个业务模块也只需要创建一个,否则就会发生混乱了。
4、线程池
grpc 的线程池。
二、门面
门面模式或者也叫外观模式。
意在屏蔽复杂性,通过一个简洁的门面与外界进行交互。
1、信息输出
比如,另外一个客服系统需要调取系列的用户信息,包括基本信息,注册、登录信息,粉丝、关注信息,认证信息等等。
对于业务组来说,可能每一项都有现成的接口输出。
但是,如果直接将这么老多接口直接丢出去,似乎也显得有些不合适:信息整合容易出问题;繁多的接口交互浪费网络资源,影响业务响应时延,也容易破坏信息展现的完整性。
这里就可以将所需的不同信息接口逻辑进行整体的封装,输出一个单一的功能接口来做门面接口。
2、Netty 的 Channel
Channel是一个接口,而且是一个很大的接口,我们称之为“大而全”,囊括了server端及client端接口所需要的接口。
Channel是一个门面,封装了包括网络I/O及相关的所有操作。
Channel聚合了包括网络读写、链路管理、网络连接信息、获取EventLoop、Pipeline等相关功能类;统一分配,调度实现相应场景的功能。
3、BeanDefinitionLoader
BeanDefinitionLoader 用于从底层资源加载 bean 定义信息,包括 xml、JavaConfig。
是基于 AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader、ClassPathBeanDefinitionScanner 的门面模式。
三、观察者
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式
1、Guava EventBus
用户信息修改后刷新整体缓存。
为什么使用它?
首先是异步需求:同步有针对性的信息修改。整体刷新逻辑作为缓存一致性数据保障不应该占用同步业务逻辑。
其次是解耦:用户信息比较冗繁,相应的 reload 逻辑牵涉业务甚多。所以将这部分逻辑进行解耦分离。
2、ApplicationListener
Spring ApplicationListener 应用事件监听接口,基于标准的 EventListener 接口,观察者模式实现。
ApplicationContext 通过 ApplicationEvent 类及 ApplicationListener 接口来处理事件。容器内实现了 ApplicationListener 接口的对象能够获取任何 ApplicationEvent 发布的事件。
四、策略
将军,我这里有锦囊三个,你且随身带着,路遇天门,打开锦囊一,得扣天门;路遇地门,打开锦囊二,得扣地门;路遇人门,打开锦囊三,得扣人门。
策略模式针对同一应用场景存在多种处理方式的情景。
1、发短信
一个公司会接很多外部短信通道,阿里、Tencent、Twilio 等。
发送方可能会指定特定的短信通道;发送手机号可能地属国内或者或外;
针对这种应用场景,就可以根据相应的入参选取不同的短信通道执行相应的发送操作。
3、行为验证
针对不同用户风险特征,执行不同的安全级别验证。
极验验证的滑块、点选、语序、空间推理等。
3、JDK Comparator
Collections.sort(List
根据传入的 Comparator 比较器对相应的列表进行排序