1.容易忘得设计原则
接口隔离:指接口中的功能太杂则可以拆分一下。防止实现类实现了接口后自动依赖了一些不需要的功能。不同功能拆分成不同的接口。
里氏代换:强调父类能出现的地方,子类一定能正常跑。
迪米特法则:又称最少知识原则,只与直接朋友通信,提高模块独立性。
单一职责,合成复用,开闭原则
依赖倒转: 指聚合/组合时使用抽象而非具体的子实现类。对抽象编程。降低客户与实现模块之间的藕合。“父类引用指向子类对象” 这说明 依赖倒转结合使用了里氏代换原则。
2、控制反转,指我写了一套抽象的支付代码,spring帮我去管理是阿里支付还是微信支付。
这个概念建立在依赖倒转原则上。即编码基于抽象。
依赖倒转是说我依赖的时候不依赖具体实现了,我依赖倒转了,变成了依赖抽象。控制反转强调的是谁创建对象。比如由容器进行构造器注入,setter注入等。
我先依赖倒转,依赖抽象支付工具,写抽象代码,然后控制反转注入bean交给spring。这样我的工作就大大简化。不需要自己去太多关注支付方式。
3.关于适配器模式 与 桥接模式的联系与区别。
适配器的典型用法: 事后补救,解决接口不兼容的问题。
class Adapter implements NewInterface {
private LegacyClass legacyObj;
适配器类实现新接口,但是组合老的实现类。通过老的实现类的方法作为input,经过一定的转换,来返回新接口方法格式的结果。
桥接模式的典型用法:事前规划。选取一个主维度作为主体,去组合其他的维度。
抽象层与实现分离。比如统一的UI框架与不同OS的渲染。统一的数据格式与不同的db 驱动。
或者是多维度的分离,防止类爆炸。比如形状与颜色,车的类型与引擎的类型。
二者也经常结合使用。比如桥接模式定义一个抽象层,如数据存储,然后组合一个Adaptor类型的实现层。
这样在实现一个具体数据存储的时候,可以去组合不同驱动类型的adaptor。
回过头来,简单总结,这个桥接模式就是用抽象组合抽象。从而减少类定义的复杂度。
4.关于单一职责原则和接口隔离原则的练习与区别。
两者都体现了高内聚,低耦合理念。
但是单一职责强调类的职责,比如订单类与支付类的拆分。
接口隔离原则强调接口的拆分,比如飞行功能与汽车行驶的接口功能拆分。
5.访问者模式:
一句话总结: 不想在猫,狗类中写关于 健康检查,喂食等代码。
简单写一个accept 方法。调用入参的Visit。
具体的健康检查,喂食,由入参类负责。
另外一般会有一个动物园类来组合元素集合。并提供依次accept的方法。方便兽医、喂食人员调用。
适合于你有一堆类似的元素(猫狗等),然后你又想将来以不同的方式来批量对待他们。
精髓是将操作从数据结构中分离出来,适用于操作易变,但数据结构稳定的系统。比如编译器,UI框架。
规避场景:数据结构容易变,或者不可预知的场景。即猫狗易变,而且我也不知道啥时候集合里面会多来一种动物。
备忘录类 典型例子是游戏存档
存储游戏状态快照,但是不想让其他人访问,随意修改数据。
Momento 对象,对其他人如玩家提供窄接口,仅对发起人(游戏程序员、GM、或者是数据敏感的GAMEROLE类这样的角色等)提供宽接口。
在java中的实现方案是,将PrivateMomento 设计为 GM类的成员内部类。
GM对外提供的backup restore 都是Momento类型。实际GM进行操作时,强转为PrivateMomento再在内部方法中偷偷操作属性等。
精髓:针对同样一个操作,实现双接口。对不同类暴漏的功能数量不一样。增强安全性。
对于无关的人,我给你一个功能很少的接口类。等到了底层真正执行的时候,你会发现它强转了向下转型了另外一个功能更强大的类。
7.状态模式
把状态抽象成类,对于同一个方法,当前是什么状态干什么事,减少if else 的使用。
比如向前Go订单。-> 现在是下单那就发货,是发货那就签收。
8.命令模式。
用一个 含有execute的 Command 接口。来解耦请求的发起与执行。
让请求的发起,关注命令即可,而不需要关注谁执行,如何去执行。
比如灯 implemens Command {
execute{ 灯.on }}
看了jdk 21的代码。 Collection 接口继承了 Iterable 接口。
public interface Collection extends Iterable
所以所有的集合类都支持迭代器。
责任链模式典型场景: 多层审批
实际精髓是一个很复杂的活,我只要请求一次就行了。
典型写法 abstract class Handler{setNext(Handler)}
细分有纯(经典审批),不纯(如filter),动态排序的链(插件化架构)等。
DEBUG日志→控制台,ERROR日志→邮件+文件。
Web请求过滤
Servlet Filter链:身份验证→参数校验→业务处理。
拓展知识,filter依赖Servlet规范的doFilter函数,依赖 Servlet容器,可以拦截静态资源。
Interceptor基于动态代理实现。依赖Spring框架,仅拦截Contoller请求(springBoot2.0之前。后来的版本需要手动放行一下)。可以访问Handler,ModelAndView等Spring上下文。
执行流程与顺序
Filter:
请求 → Tomcat容器 → Filter → Servlet
多个Filter按配置顺序链式执行(责任链模式)
Interceptor:
请求 → DispatcherServlet → Interceptor.preHandle() → Controller → Interceptor.postHandle() → 视图渲染 → Interceptor.afterCompletion()
支持更细粒度的生命周期控制(如preHandle返回false可中断请求)。
请求先经过Filter才进入DispatcherServlet。
所以先Fileter后intercepter。
掌握两者生命周期差异(Filter在Servlet前后,Interceptor在Controller前后),并强调Interceptor与Spring的协同优势(如Bean注入、路径精确控制)。实际项目中常组合使用,例如Filter处理全局安全,Interceptor处理业务权限。
模板方法:
父类定义算法骨架,并允许子类重写特定步骤。在源码中应用广泛。
AbstractApplicationContext类中的finishBeanFactoryInitialzation方法调用了子类的getBean方法。因为getBean的实现与环境息息相关。具体的实现类有classPathXMLApplicationContext的基于XML配置的。或者基于配置类+注解方式的AnnotationConfigWebApplicationContext。
抽象类InputStream类中定义了read方法。
需要子类去实现。但是read前后还有一些其他逻辑,子类就不需要去关注了。比如读多少字节,什么时候停止。子类只要保证能正确读取一个字节即可。
HttpServlet中的 doGet doPost交给子类实现。子类专注于业务细节。
HttpServlet比较老的概念,原生Servlet开发痛点是每个Servlet需要独立配置web.xml路由映射。
而SpringMVC 通过@requestMapping注解替代配置。
底层依赖关系:
Controller 的调用依赖 DispatcherServlet(HttpServlet 的子类),但 Controller 并非 Servlet 的直接实现。
Controller 是 Spring MVC 对 Servlet 的高层抽象,通过注解和框架机制简化开发,提升可维护性。让程序员专注于业务细节,忽略协议处理。
12。常见应用场景:spring Spel源码, jdk正则, mybitis sql解析引擎。缺点是太负责的语法在性能上难以支撑。其价值在于为特定领域语言提供轻量级解析方法。
将运算、变量都定义为对象
将表达式解析为 表达式 运算符 表达式。递归的去运算,直到能算出结果,简单的使用了递归。性能比较差。
13.手写策略模式
要记得有个环境类。聚合了策略。
可以set策略,执行策略。
表达时,可以说字节切换推荐策略,比如按热度,时间,相关性。
加分项:配置中心,热更新。
工厂模式+配置文件解决策略类过多的问题。
缺点是客户端要了解策略。
java关键字都是小写
public interface SortingStrategy{
void sort (int data);
}
BubbleSort
@Override
QuickSort
@Override
SortContext
setStrategy
executeSort
public class StrategyDemo
public class StrategyDemo {
public static void main(String[] args) {
int[] data = {5, 2, 9, 1, 5};
SortContext context = new SortContext();// 动态切换策略context.setStrategy(new BubbleSort());context.executeSort(data); // 输出:使用冒泡排序context.setStrategy(new QuickSort());context.executeSort(data); // 输出:使用快速排序
}
}