目录
2、动态代理(动态代理是在程序运行时通过反射机制动态创建的。)
一、六大设计原则
- 单一职责原则(Single Responsibility Principle)
-
- 一个类只负责一项职责,仅有一个引起它变化的原因。
- 例:用户类(
User)只管理用户信息,不应包含订单处理逻辑(应交给订单类)。
- 开放 - 封闭原则(Open-Closed Principle)
-
- 对扩展开放(可新增功能),对修改关闭(不改动原有代码)。
- 例:通过接口定义支付行为(
IPay),新增 “支付宝” 支付时只需实现接口,无需修改原有支付流程。
- 里氏替换原则(Liskov Substitution Principle)
-
- 子类可替换父类,且替换后不改变原有程序的正确性。
- 反例:正方形类继承长方形类,修改正方形的 “宽” 会同时改变 “长”,违反长方形的逻辑。
- 接口隔离原则(Interface Segregation Principle)
-
- 避免 “臃肿接口”,应拆分为多个专用接口,客户端只需依赖所需接口。
- 例:将 “动物接口” 拆分为 “会飞接口”“会跑接口”,鸟实现前者,狗实现后者。
- 依赖倒置原则(Dependency Inversion Principle)
-
- 依赖抽象(接口 / 抽象类),而非具体实现;高层模块不依赖低层模块。
- 例:服务层依赖
IUserDao接口,而非具体的MysqlUserDao或OracleUserDao。
- 迪米特法则(Law of Demeter)
-
- 一个对象应尽可能少地了解其他对象(只与直接朋友通信)。
- 例:学生类无需直接操作课程的数据库访问,应通过 “班级管理类” 间接获取课程信息。
二、23 种设计模式(按类型分类)
1. 创建型模式(5 种):处理对象创建,隐藏创建逻辑
- 单例模式(Singleton)
确保类只有一个实例,并提供全局访问点。
应用:Spring 的Bean默认单例、日志工具类。 - 工厂方法模式(Factory Method)
定义创建对象的接口,由子类决定实例化哪个类。
应用:Spring 的BeanFactory(通过不同实现类创建不同类型的 Bean)。 - 抽象工厂模式(Abstract Factory)
提供一个接口,用于创建一系列相关 / 依赖对象,无需指定具体类。
应用:数据库访问层(同时创建 Connection、Statement 等配套对象)。 - 建造者模式(Builder)
分步构建复杂对象,分离对象的构建与表示。
应用:StringBuilder、 Lombok 的@Builder注解。 - 原型模式(Prototype)
通过复制现有对象创建新对象(避免重复初始化)。
应用:Spring 的Bean作用域(prototype原型模式)。
2. 结构型模式(7 种):处理类或对象的组合,优化结构
- 适配器模式(Adapter)
将一个类的接口转换为客户端期望的另一个接口,解决兼容性问题。
应用:InputStreamReader(将字节流适配为字符流)。 - 装饰器模式(Decorator)
动态给对象添加功能,不改变原有类结构。
应用:BufferedInputStream(为输入流添加缓冲功能)。 - 代理模式(Proxy)
为对象提供代理,控制对原对象的访问(如权限、延迟加载)。
应用:Spring AOP 动态代理、MyBatis 的 Mapper 代理。 - 外观模式(Facade)
提供一个统一接口,简化复杂系统的调用。
应用:电脑启动(只需调用 “启动” 方法,内部自动处理 CPU、内存、硬盘初始化)。 - 桥接模式(Bridge)
将抽象与实现分离,使两者可独立变化。
应用:图形界面(形状抽象类与渲染实现类分离,可分别扩展)。 - 组合模式(Composite)
树形结构中,统一处理单个对象和组合对象。
应用:文件夹结构(文件和文件夹统一视为 “节点” 操作)。 - 享元模式(Flyweight)
复用细粒度对象,减少内存消耗(共享不变部分)。
应用:字符串常量池(相同字符串复用同一对象)。
3. 行为型模式(11 种):处理对象间交互,优化行为协作
- 策略模式(Strategy)
定义算法族,动态选择使用哪种算法(消除大量if-else)。
应用:电商折扣系统(不同会员等级对应不同折扣策略)。 - 模板方法模式(Template Method)
父类定义算法骨架,子类实现具体步骤。
应用:JdbcTemplate(封装 JDBC 固定流程,留自定义 SQL 执行逻辑)。 - 观察者模式(Observer)
定义一对多依赖,一个对象变化时通知所有依赖者。
应用:Spring 事件机制(ApplicationEvent与Listener)。 - 迭代器模式(Iterator)
提供遍历集合的统一接口,隐藏集合内部结构。
应用:Java 集合的Iterator接口。 - 责任链模式(Chain of Responsibility)
多个对象处理请求,形成链条,每个对象决定是否处理或传递给下一个。
应用:过滤器(Filter)链、日志级别处理(DEBUG→INFO→ERROR)。 - 命令模式(Command)
将请求封装为对象,使请求可参数化、队列化或撤销。
应用:线程池的Runnable(任务命令化)、遥控器按钮(每个按钮对应一个命令)。 - 备忘录模式(Memento)
保存对象状态,以便后续恢复。
应用:编辑器的撤销功能(保存文本历史状态)。 - 状态模式(State)
对象状态变化时,动态改变其行为(将状态逻辑封装为不同类)。
应用:订单状态流转(待支付→已支付→已发货→已完成)。 - 访问者模式(Visitor)
在不修改类的前提下,为类添加新操作(分离数据结构与操作)。
应用:报表生成(同一组数据,生成不同格式报表)。 - 中介者模式(Mediator)
用中介者对象封装对象间的交互,减少直接依赖。
应用:MVC 中的 Controller(中介者,协调 View 与 Model)。 - 解释器模式(Interpreter)
定义语言语法的解释器,用于解析特定格式的语句。
应用:表达式解析(如数学公式、SQL 解析器)。
三、设计原则与模式的关系
- 设计原则是 “道”,指导设计的方向(如高内聚、低耦合);设计模式是 “术”,是原则的具体实现方案。
- 例如:
-
- 开放 - 封闭原则 → 策略模式、装饰器模式;
- 依赖倒置原则 → 工厂模式、抽象工厂模式;
- 迪米特法则 → 外观模式、中介者模式。
四、常用的设计模式
1、单例模式
①懒汉式: 用的时候new对象,
package com.ape.danli.lanhanshi;
public class Student3 {
//懒汉式,用的时候new 不用不new
private String name;
private static Student3 stu;
public static synchronized Student3 getInstance(){
if(stu==null){
stu=new Student3();
}
return stu;
}
}
②饿汉式: 一开始就new好,直接使用
package com.ape.danli.ehanshi;
public class Student2 {
//饿汉式,直接new
private static final Student2 stu=new Student2();
public static synchronized Student2 getInstance(){
return stu;
}
}
2、工厂模式
- 创捷接口或者父类(通过父子类或者接口实现)
package com.ape.duoli;
public interface Nooodle {
public void noodleType();
}
- 创建实现类实现接口中的方法(三种面条 youpo regan lanzhounurou)
package com.ape.duoli;
public class ReGan implements Nooodle{
public void noodleType() {
System.out.println("=======热干面========");
}
}
package com.ape.duoli;
public class YouPo implements Nooodle{
@Override
public void noodleType() {
System.out.println("=======油泼面========");
}
}
package com.ape.duoli;
public class LanZhouNuRou implements Nooodle{
public void noodleType() {
System.out.println("=======兰州牛肉面========");
}
}
- 创建工厂类(面条工厂),生产不同的实现类对象(生产不同种类的面条)
package com.ape.duoli;
import sun.dc.pr.PRError;
public class NoodlesFactory {
// 定义静态常量标记类型
public static final int REGAN_TYPE = 1;
public static final int YOUPO_TYPE = 2;
public static final int LANZHOUNUROU_TYPE = 3;
//生产面条对象
public static Nooodle NoodleType(int type) {
if (type == 1) {
return new ReGan();
}
if (type == 2) {
return new YouPo();
}
if (type == 3) {
return new LanZhouNuRou();
}
return null;
}
}
- 测试类:
package com.ape.duoli;
import static com.ape.duoli.NoodlesFactory.LANZHOUNUROU_TYPE;
import static com.ape.duoli.NoodlesFactory.YOUPO_TYPE;
public class Test {
public static void main(String[] args) {
NoodlesFactory.NoodleType(1).noodleType();
NoodlesFactory.NoodleType(YOUPO_TYPE).noodleType();
Nooodle nooodle = NoodlesFactory.NoodleType(LANZHOUNUROU_TYPE);
nooodle.noodleType();
}
}
3、模板模式
父类定义算法骨架,子类实现具体步骤。
应用:JdbcTemplate(封装 JDBC 固定流程,留自定义 SQL 执行逻辑)
- 创建父类
package com.ape.moban;
public abstract class Father {
public final void 人生(){
学习();
工作();
爱情();
}
public void 学习(){
System.out.println("父亲: 需要学习");
}
public void 工作(){
System.out.println("父: 需要工作");
}
public abstract void 爱情();
}
- 创建子类,子类通过重写或者调用父类被final修饰的方法
package com.ape.moban;
public class Son extends Father {
@Override
public void 爱情() {
System.out.println("子:撒浪嘿呦");
}
public void 学习() {
System.out.println("子:好好学习天天向上");
}
}
4、代理模式
1、含义:
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,通俗的来讲代理模式就是我们生活中常见的中介。
2、作用
- 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 增强方法(开闭原则,增加功能): 代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代,理类而不需要再修改委托类,符合代码设计的开闭原则。
3、代理模式
1、静态代理
- 静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了。
案例:
- 创建接口 代理对象与被代理对象同属于一个接口或一个父类
package com.ape.daili.staticdaili;
public interface IWoman {
public void makeEyesWithMan();
}
- 创建实现类潘金莲(被代理对象)
public class PanJingLian implements IWoman{
@Override
public void makeEyesWithMan() {
System.out.println("===========回眸一笑百媚生============");
}
}
- 创捷王婆类(代理对象)
public class WangPo implements IWoman {
private IWoman woman;
public WangPo(IWoman woman) {
this.woman = woman;
}
@Override
public void makeEyesWithMan() {
System.out.println("王婆:我给你找潘金莲!");
woman.makeEyesWithMan();
}
}
- 创建西门庆测试类
public class XiMenQing {
public static void main(String[] args) {
PanJingLian panJingLian = new PanJingLian();
WangPo wangPo = new WangPo(panJingLian);
wangPo.makeEyesWithMan();
}
}
2、动态代理(动态代理是在程序运行时通过反射机制动态创建的。)
- 创建接口类型
public interface ISinger {
public void sing();
public void eat();
}
- 基于接口的动态代理(jdk自带)
package com.ape.daili.dongtaidaili;
public class CaiXuKun implements ISinger{
@Override
public void sing() {
System.out.println("==========鸡你太美=============");
}
public void eat(){
System.out.println("鸡你太美,我要吃鸡");
}
}
package com.ape.daili.dongtaidaili;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理====》jdk自带Proxy
* */
/**
* 基于接口的动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改源码的基础上对方法增强
* 涉及的类:Proxy
* 提供者:JDK官方
* 如何创建代理对象:
* 使用Proxy类中的newProxyInstance方法
* 创建代理对象的要求:
* 被代理类最少实现一个接口,如果没有则不能使用
* newProxyInstance方法的参数:
* ClassLoader:类加载器
* 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
* Class[]:字节码数组
* 它是用于让代理对象和被代理对象有相同方法。固定写法。
* InvocationHandler:用于提供增强的代码
*
*/
public class Test {
public static void main(String[] args) {
CaiXuKun kun = new CaiXuKun();
ISinger JInjiren=(ISinger) Proxy.newProxyInstance(kun.getClass().getClassLoader(), kun.getClass().getInterfaces(), new InvocationHandler() {
/***
* Object proxy=====》被代理对象的引用===(蔡徐坤对象)
* Method method====》执行的方法========(蔡徐坤唱歌方法)
* Object[] args====》执行方法的参数=====(蔡徐坤唱歌方法的参数)
* Object===========》执行方法的返回值===(蔡徐坤唱歌方法的返回值)
* */
/**
* 作用:执行被代理对象的任何接口方法都会经过该方法
* 方法参数的含义
* proxy 代理对象的引用
* method 当前执行的方法
* args 当前执行方法所需的参数
* Object 和被代理对象方法有相同的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("sing")){
System.out.println("蔡徐坤正在唱歌");
}
System.out.println("我是蔡徐坤");
Object obj = method.invoke(kun, args);
return obj ;
}
});
//接口中的方法
JInjiren.sing();
JInjiren.eat();
}
}
- 基于子类的动态代理(第三方)需要导入依赖(cglib)
public class ZhouShen implements ISinger{
@Override
public void sing() {
System.out.println("周深在唱歌");
}
@Override
public void eat() {
System.out.println("周深在吃饭");
}
}
package com.ape.daili.dongtaidaili;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
public class Test2 {
//基于外部坏境的动态代理
/**
* 基于子类的动态代理
* 涉及的类:Enhancer
* 提供者:第三方cglib库
* 开发环境:添加cglib依赖坐标
* 如何创建代理对象:
* 使用Enhancer类中的create方法
* 创建代理对象的要求:
* 被代理类不能是最终类
* create方法的参数:
* Class:字节码
* 它是用于指定被代理对象的字节码。
*
* Callback:用于提供增强的代码
* 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写。
* 我们一般写的都是该接口的子接口实现类:MethodInterceptor
*
*/
public static void main(String[] args) {
ZhouShen shen = new ZhouShen();
/**
* 2.创建代理对象
* 参数1:被代理对象的字节码
* 参数2:InvocationHandler
* */
/**
* 执行北地阿里对象的任何方法都会经过该方法
* @param proxy
* @param method
* @param args
* 以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
* @param methodProxy :当前执行方法的代理对象
* @return
* @throws Throwable
*/
ISinger jPeople=(ISinger) Enhancer.create(shen.getClass(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("我是周深");
Object object = method.invoke(shen, objects);
if(method.getName().equals("sing")) {
System.out.println("代表作大鱼海棠");
}
return object;
}
});
jPeople.sing();
jPeople.eat();
}
}

被折叠的 条评论
为什么被折叠?



