设计模式 -详解

1.单例模式

单例模式是指在整个应用中一个类的对象只允许出现一个(类的对象最多 只允许创建一次);

我们在创建一个类的对象时,调用的是类的构造器,所以在单例中类的构 造器只允许调用一次 **核心:**构造方法私有化,不允许在外部创建类的实例,而将类的实例构建 放到类内部实现,在内部通过编码控制实例的创建只能创建一次。

1.1饿汉模式

它是一种对象立即加载(对象立即创建)模式,当类被加载 时该单例对象就被创建,时间效率比较高,空间效率低

复制代码
 package com.jiazhong.basic.设计模式.单例模式;
 ​
 public class 饿汉单例模式 {
     private static 饿汉单例模式 instence=new 饿汉单例模式();
     private 饿汉单例模式(){}
 ​
     public static 饿汉单例模式 getInstance(){
         return instence;
     }
 }

1.2懒汉模式

它使用的是懒加载模式实现的单例,当需要使用类对象时 才创建该类的单例对象(时间效率比较低,空间效率高)

复制代码
 package com.jiazhong.basic.设计模式.单例模式;
 ​
 import lombok.SneakyThrows;
 ​
 public class 懒汉单例模式 {
     private static 懒汉单例模式 instance;
     private static Object suo=new Object();
 ​
     private 懒汉单例模式() {
     }
     @SneakyThrows
     public static 懒汉单例模式 getInstance(){
         if (instance==null){
             synchronized (suo){
                 if (instance==null){
                     Thread.sleep(100);
                     instance=new 懒汉单例模式();
                 }
             }
         }
         return instance;
     }
 ​
 }

1.3枚举单例模式

复制代码
 package com.jiazhong.basic.设计模式.单例模式;
 ​
 public enum 枚举单例模式 {
     INSTANCE;
 ​
     public void a(){
         System.out.println("Hello");
     }
 ​
     public void find(){
         System.out.println("find");
     }
 }

测试类

复制代码
 package com.jiazhong.basic.设计模式.单例模式;
 ​
 import lombok.SneakyThrows;
 ​
 import java.lang.reflect.Constructor;
 ​
 public class App {
 ​
     private static void a(){
         饿汉单例模式 i1=饿汉单例模式.getInstance();
         饿汉单例模式 i2=饿汉单例模式.getInstance();
         System.out.println(i1);
         System.out.println(i2);
         System.out.println(i1==i2);
     }
     private static void b1(){
         懒汉单例模式 i1=懒汉单例模式.getInstance();
         懒汉单例模式 i2=懒汉单例模式.getInstance();
         System.out.println(i1);
         System.out.println(i2);
         System.out.println(i1==i2);
     }
     @SneakyThrows
     private static void b2(){
         final 懒汉单例模式[] i=new 懒汉单例模式[2];
         Thread t1=new Thread(() -> i[0] =懒汉单例模式.getInstance());
         Thread t2=new Thread(() -> i[1] =懒汉单例模式.getInstance());
         t1.start();
         t2.start();
         Thread.sleep(1000);
         System.out.println(i[0]);
         System.out.println(i[1]);
         System.out.println(i[0]==i[1]);
     }
     @SneakyThrows
     private static void c1(){
         Class<?> aClass=Class.forName("com.jiazhong.basic.设计模式.单例模式.饿汉单例模式");
         Constructor<?> constructor=aClass.getDeclaredConstructor();
         constructor.setAccessible(true);
         Object o1=constructor.newInstance();
         Object o2=constructor.newInstance();
         System.out.println(o1);
         System.out.println(o2);
         System.out.println(o1==o1);
     }
     private static void c2(){
         枚举单例模式 i1=枚举单例模式.INSTANCE;
         枚举单例模式 i2=枚举单例模式.INSTANCE;
         System.out.println(i1);
         System.out.println(i2);
         System.out.println(i1==i2);
         i1.a();
         i1.find();
     }
 ​
     public static void main(String[] args) {
         c2();
     }
 }

2.工厂模式

工厂模式分为工厂方法模式和抽象工厂模式(创建型模式)

优点:实现对象的创建和对象的使用分离。将对象的创建交给专门的工厂进行。

产生对象和使用对象分离

3.代理模式

代理模式属于结构型设计模式。

代理模式是指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。可以理解为中介。

3.1静态代理模式

静态代理是指代理类由开发人员创建,在程序运行前代理对象已被创建;

自己写一个类去实现接口

复制代码
 接口 请客
 package com.jiazhong.basic.设计模式.代理模式.静态代理;
 ​
 public interface Treat {
     void treat();
 }
复制代码
 老板实现接口
 package com.jiazhong.basic.设计模式.代理模式.静态代理;
 ​
 public class Boss implements Treat{
     @Override
     public void treat() {
         System.out.println("我是老板,今天我请客吃饭");
     }
 }
复制代码
 助理实现接口(代理类)
 package com.jiazhong.basic.设计模式.代理模式.静态代理;
 ​
 public class Assistant implements Treat{
     private Boss boss;
 ​
     public Assistant(Boss boss) {
         this.boss = boss;
     }
 ​
     @Override
     public void treat() {
         boss.treat();
         System.out.println("老板不在,我来付钱");
     }
 }
 ​
复制代码
 //测试
 package com.jiazhong.basic.设计模式.代理模式.静态代理;
 ​
 public class App {
     public static void main(String[] args) {
         Boss boss=new Boss();//老板
         Assistant assistant=new Assistant(boss);//助理代替老板
         assistant.treat();
     }
 }
 ​

treat应该调用boss但boss没在,调用Assistant,Assistant可以代替boss实现treat方法

3.2动态代理

3.2.1基于JDK实现(重点)

动态代理把接口写好之后,程序在运行过程中会自动地产生当前接口的代理对象。

动态代理是指代理对象在程序运行时通过反射机制(Proxy)动态创建 。 动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器(InvocationHandler) 就可以了。真正的代理对象由 JVM 在运行时为我们动态的来创建。(自动)

JDK实现的动态代理只支持接口代理,不支持类的代理

复制代码
 动态代理类
 package com.jiazhong.basic.设计模式.代理模式.动态代理.jdk;
 ​
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 //动态代理 拦截器
 public class DynamicProxyHandler implements InvocationHandler {
     //代理人
     private Object obj;
     public DynamicProxyHandler(Object obj){
         this.obj=obj;
     }
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         System.out.println("我是助理,今天老板不在,我来付钱");
         System.out.println("用户调用的方法是:"+method.getName());
         System.out.println("用户传递的参数是:"+ Arrays.toString(args));
         //调用目标对象方法
         return method.invoke(obj,args);
     }
 }
 ​
复制代码
 测试
 package com.jiazhong.basic.设计模式.代理模式.动态代理.jdk;
 ​
 import com.jiazhong.basic.设计模式.代理模式.动态代理.cjlib.Boss;
 ​
 import java.lang.reflect.Proxy;
 ​
 public class App {
     public static void main(String[] args) {
         //目标对象
         Boss boss=new Boss();
         //1.classLoader
         ClassLoader classLoader=Treat.class.getClassLoader();
         //2.boss实现的接口
         Class[] classes={Treat.class};
         //3.proxyHandler对象
         DynamicProxyHandler proxyHandler=new DynamicProxyHandler(boss);
         Treat treat=(Treat) Proxy.newProxyInstance(classLoader,classes,proxyHandler);
         System.out.println(treat);
         treat.diancai("鱼香肉丝");或treat.treat();
     }
 }
3.2.3CGLIB代理

CGLIB 代理也是一种动态代理,该代理支持使用类的子类做为代理对象。 CGLIB 采用了非常底层的字节码技术 ,其原理是通过字节码技术为一个类创建子类 ,并在子类中采用方法拦截的技术 拦截所有父类方法的调用, 顺势织入横切逻辑。但因为采用的是继承,所以不能对 final 修饰的类 进行代理。JDK 动态代理与 CGLib 动态代理均是实现 Spring AOP 的基础。 Enhancer 是一个非常重要的类,它允许为非接口类型创建一个 JAVA 代 理,Enhancer 动态的创建给定类的子类并且拦截代理类的所有的方法, 和 JDK 动态代理不一样的是不管是接口还是类它都能正常工作。

复制代码
 导依赖 AOP
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-aop</artifactId>
             <version>6.1.1</version>
         </dependency>
复制代码
 package com.jiazhong.basic.设计模式.代理模式.动态代理.cjlib;
 ​
 import org.springframework.cglib.proxy.MethodInterceptor;
 import org.springframework.cglib.proxy.MethodProxy;
 ​
 import java.lang.reflect.Method;
 ​
 //动态代理类
 public class CGLibProxyHandler implements MethodInterceptor  {
 ​
     @Override
     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
         System.out.println("今天老板不来,我来付钱");
         return proxy.invokeSuper(obj,args);
     }
 }
复制代码
 测试类
 package com.jiazhong.basic.设计模式.代理模式.动态代理.cjlib;
 import org.springframework.cglib.proxy.Enhancer;
 public class App {
     public static void main(String[] args) {
         //拦截器的代理方式通过继承的方式实现 继承treat
         Enhancer enhancer=new Enhancer();
         //设置其父类
         enhancer.setSuperclass(Boss.class);
         //设置回调
         enhancer.setCallback(new CGLibProxyHandler());
         //创建代理对象
         Boss treat=(Boss) enhancer.create();
         treat.a();
     }
 }
3.2.3手撕MyBatis
复制代码
 package com.jiazhong.basic.设计模式.代理模式.动态代理.手撕Mbatis.handler;
 ​
 import java.io.File;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 ​
 public class SqlSession implements InvocationHandler {
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         String methodName=method.getName();
         if ("add".equals(methodName)){
             Object arg = args[0]; // 参数 对象
             Class cl = arg.getClass(); // 类
             String className = cl.getSimpleName(); // tableName 类名==表名
             Field[] declaredFields = cl.getDeclaredFields(); // 获取到所有定义的属性
             String columns = "";
             String values = "";
             for (int i = 0; i < declaredFields.length; i++) {
                 System.out.println("---------------------------------------------------");
                 Field declaredField = declaredFields[i];
                 System.out.println(declaredField);
                 String fieldName = declaredField.getName();
                 System.out.println(fieldName);
                 columns += fieldName + ","; // id--->getId  name--->getName toUpperCase大写
                 String methodGetName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                 System.out.println(methodGetName);
                 Method getMethod = cl.getDeclaredMethod(methodGetName);
                 Object result = getMethod.invoke(arg);
                 System.out.println(result);
                 values += "'" + result + "',";
             }
             //去逗号
             columns = columns.substring(0, columns.length() - 1);
             values = values.substring(0, values.length() - 1);
             // 执行添加操作
             String sql = "insert into " + className + "(" + columns + ") values(" + values + ")";
             System.out.println(sql);
             //执行
         }
 ​
         return null;
 ​
     }
     //获取到具体mapper接口的“代理”对象
     //给什么类的类型,会将这个类的具体类型的对象返回出来
     public <T> T getMapper(Class<T> tClass){
         ClassLoader classLoader=tClass.getClassLoader();
         Class[] classes={tClass};
         return (T) Proxy.newProxyInstance(classLoader,classes,this);
     }
 }
 ​

4.观察者模式

判断库存:rocketmq的延迟消息、观察者模式订阅消息机制、Ai行为

观察者模式:指多个对象之间存在一对多的依赖关系,当一个对象( 服务器|主题)的状态发生改变时, 所有依赖它的对象(客户端|观察者)都能自动收到通知并 根据通知来决定自己行为。这种模式有时又被称 为**"发布-订阅模式** "、"模型-视图模式"。

主题 变化了观察者会收到通知,分别写成抽象类和具体实现类。

实例:购买彩票

复制代码
 抽象主题
 package com.jiazhong.basic.设计模式.观察者模式;
 ​
 public interface 抽象主题 {
     void 注册观察者(抽象观察者 gcz);
     void 通知观察者();
 }
复制代码
 彩票主题
 package com.jiazhong.basic.设计模式.观察者模式;
 ​
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 ​
 public class 彩票主题 implements 抽象主题{
     private List<抽象观察者> list=new ArrayList<>();
     @Override
     public void 注册观察者(抽象观察者 gcz) {
         list.add(gcz);
     }
 ​
     @Override
     public void 通知观察者() {
         int number=(int) (Math.random()*33+1);
         list.forEach(e->{
             e.接收通知(number);
         });
     }
 }
复制代码
 抽象观察者
 package com.jiazhong.basic.设计模式.观察者模式;
 ​
 public interface 抽象观察者 {
     void 接收通知(int number);
 }
复制代码
 具体观察者(彩民观察者)
 package com.jiazhong.basic.设计模式.观察者模式;
 ​
 public class 彩民观察者 implements 抽象观察者{
     private int number=(int)(Math.random()*33+1);
     private int id;
 ​
     public 彩民观察者(int id) {
         this.id = id;
     }
 ​
     @Override
     public void 接收通知(int number) {
         System.out.println("这个彩民购买的号码是:"+this.number);
         System.out.println("本次开奖结果是:"+number);
         System.out.println(this.number==number?"恭喜你,中奖了":"很遗憾,下次努力");
     }
 }
复制代码
 测试类
 package com.jiazhong.basic.设计模式.观察者模式;
 ​
 import lombok.SneakyThrows;
 ​
 public class App {
     @SneakyThrows
     public static void main(String[] args){
         抽象主题 zhuti=new 彩票主题();
         for (int i = 0; i < 30; i++) {
             彩民观察者 cm1=new 彩民观察者(i+1);
             zhuti.注册观察者(cm1);
         }
         System.out.println("经过了一段时间");
         for (int i = 0; i < 10; i++) {
             Thread.sleep(300);
             System.out.println(".");
         }
         System.out.println();
         System.out.println("开始通知彩民");
         zhuti.通知观察者();
     }
 }

5.装饰者模式

装饰者模式 :动态地将责任(功能)附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案 。 (1) 装饰者被装饰对象 有相同的超类 。 (2) 你可以用一个或多个装饰者包装一个对象(被装饰者对象 )。 (3) 既然装饰者和被装饰对象有相同的超类,所以在任何需要原始对象 (被包装的)的场合,可以用装饰过的对象代替它。 (4) 装饰者可以在所委托被装饰者的行为之前与 / 或之后,加上自己的 行为,(不修改它的代码的情况下,修改了它的行为)以达到特定的目的(5) 在装饰者的行为(方法中)发起对被装饰者对象的行为(方法)的调用 (6) 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

对添加是开放的,对修改是关闭的 不修改原来的代码 将类的方法变得更强大但没有修改代码

例如:陕西人与河北人有一个共同的父类中国人,中国人能进的地方陕西人也能进,陕西人能进的地方河北人也能进。

示例:

定义一个人类

学生继承人类,学生在学习

学生不单单会学习他们其中有些人可能还具有其他能力, 如唱歌、跳舞等,我们通过装饰模式的来为不同的人群添加新的能力

复制代码
 //人
 package com.jiazhong.basic.设计模式.装饰者模式;
 ​
 public interface Person {
     void active();
 }
 ​
复制代码
 //学生类
 package com.jiazhong.basic.设计模式.装饰者模式;
 ​
 import lombok.Data;
 ​
 @Data
 public class Student implements Person{
     private String name;
 ​
     public Student(String name) {
         this.name = name;
     }
 ​
     @Override
     public void active() {
         System.out.println(name+"正在努力学习");
     }
 }
 ​
复制代码
 ​
 package com.jiazhong.basic.设计模式.装饰者模式;
 ​
 import lombok.Data;
 ​
 @Data
 public class BigStudent extends Student{
     public BigStudent(String name) {
         super(name);
     }
     @Override
     public void active(){
         super.active();
         System.out.println(super.getName()+"边唱歌边学习");
     }
 }
复制代码
 //装饰者类
 package com.jiazhong.basic.设计模式.装饰者模式;
 ​
 public class 装饰者 implements Person{
 ​
     private Person 被装饰者;
 ​
     public 装饰者(Person 被装饰者) {
         this.被装饰者 = 被装饰者;
     }
 ​
     @Override
     public void active() {
         //添加了我的功能
         System.out.println("边唱歌边学习");
         被装饰者.active();
     }
 }
复制代码
 //测试
 package com.jiazhong.basic.设计模式.装饰者模式;
 ​
 public class App {
     //继承方式
     private static void a(){
         Person p=new BigStudent("张三");
         p.active();
     }
     //装饰者方式
     private static void b(){
         Person p=new Student("张三");
         装饰者 zsz=new 装饰者(p);
         zsz.active();
     }
 ​
     public static void main(String[] args) {
         b();
     }
 }

6.责任链模式

责任链模式: 顾名思义,就是用来处理相关事务责任的一条执行链,执行链上 有多个节点,每个节点都有机会处理请求事务,如果某个节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。

示例:

员工请假审批流程: 请假时间 1 天以内,项目组长审批即可 请假时间大于 1 天小于等于 3 天,则需要项目经理审批 请假时间大于 3 天,则需要总经理审批

复制代码
 package com.jiazhong.basic.设计模式.责任链模式;
 ​
 public abstract class Handler {
 ​
     private Handler nextHandler;
     public Handler getNextHandler(){
        return nextHandler;
     }
     public void setNestHandler(Handler nextHandler){
         this.nextHandler=nextHandler;
     }
     public abstract void active(int day);//接口可以省略public,抽象类不可以
 }
 ​
复制代码
 package com.jiazhong.basic.设计模式.责任链模式;
 ​
 public class TM extends Handler{
     @Override
     public void active(int day) {
         System.out.println("组长开始审批");
         if (day>1){
             super.getNextHandler().active(day);
         }
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.责任链模式;
 ​
 public class PM extends Handler{
     @Override
     public void active(int day) {
         System.out.println("项目经理开始审批");
         if (day>3){
             getNextHandler().active(day);
         }
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.责任链模式;
 ​
 public class GM extends Handler{
     @Override
     public void active(int day) {
         System.out.println("总经理开始审批");
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.责任链模式;
 ​
 public class App {
     public static void main(String[] args) {
         GM gm=new GM();
         PM pm=new PM();
         TM tm=new TM();
         tm.setNestHandler(pm);
         pm.setNestHandler(gm);
 ​
         tm.active(2);
     }
 }

7.策略模式(锦囊妙计)

策略模式(Strategy):定义了一组算法,将每个算法都封装起来,在使 用时根据不同的环境使用不同的算法(使用时可以互换)

复制代码
 package com.jiazhong.basic.设计模式.策略模式;
 ​
 public class 旅游 {
     private 出行 出行策略;
     public 旅游(出行 出行策略){
         this.出行策略=出行策略;
     }
     public void 旅游(){
         System.out.println("我们准备去西安");
         出行策略.出行方式();
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.策略模式;
 //抽象策略
 public interface 出行 {
     void 出行方式();
 }
复制代码
 package com.jiazhong.basic.设计模式.策略模式;
 ​
 public class 高铁 implements 出行{
     @Override
     public void 出行方式() {
         System.out.println("坐着高铁回西安");
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.策略模式;
 ​
 public class 飞机 implements 出行{
 ​
     @Override
     public void 出行方式() {
         System.out.println("坐着飞机回西安");
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.策略模式;
 ​
 public class 火车 implements 出行{
     @Override
     public void 出行方式() {
         System.out.println("坐着火车回西安");
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.策略模式;
 ​
 public class App {
     public static void main(String[] args) {
         出行 cx=new 飞机();
         旅游 lv=new 旅游(cx);
         lv.旅游();
     }
 }

8.适配器模式

适配器模式是指将一个接口转换成客户希望的另一个接口,使接口不兼容 的那些类可以一起工作。(转换器)

适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问 题,使得原本没有任何关系的类可以协同工作。

实例:

充电器

复制代码
 package com.jiazhong.basic.设计模式.适配器模式;
 ​
 public interface 充电接口 {
     int output5v();
 }
复制代码
 package com.jiazhong.basic.设计模式.适配器模式;
 ​
 public class 手机 {
     public void 充电(充电接口 cdjk){
         System.out.println("手机没电了");
         int i=cdjk.output5v();
         if (i==5){
             System.out.println("手机开始充电,开始连接充电器");
             return;
         }
         System.out.println("充电电压不符合要求");
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.适配器模式;
 ​
 public class 充电器 implements 充电接口{
     private 电源 dy;
     public 充电器(电源 dy){
         this.dy=dy;
     }
     @Override
     public int output5v() {
         System.out.println("充电器将"+dy.output()+"v的电压转换成5v电压");
         return 5;
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.适配器模式;
 ​
 public class 电源 {
     public int output(){
         return 220;
     }
 }
复制代码
 package com.jiazhong.basic.设计模式.适配器模式;
 ​
 public class App {
 ​
     public static void main(String[] args) {
         电源 dy=new 电源();
         充电器 cdq=new 充电器(dy);
         手机 sj =new 手机();
         sj.充电(cdq);
     }
 }
相关推荐
夏河始溢2 小时前
一八四、Zustand 状态管理详解、与 Redux、MobX 的对比分析
前端·javascript·react.js·状态管理·zustand
froginwe112 小时前
ECharts 样式设置
开发语言
清风~徐~来2 小时前
【视频点播系统】AMQP-SDK 介绍及使用
开发语言
进击的小头2 小时前
设计模式落地的避坑指南(C语言版)
c语言·开发语言·设计模式
凤年徐2 小时前
容器适配器深度解析:从STL的stack、queue到优先队列的底层实现
开发语言·c++·算法
ujainu2 小时前
Flutter + OpenHarmony 游戏开发进阶:虚拟摄像机系统——平滑跟随与坐标偏移
开发语言·flutter·游戏·swift·openharmony
Code小翊2 小时前
TypeScript 核心语法速查
前端·javascript·typescript
短剑重铸之日2 小时前
《设计模式》第五篇:策略模式
java·后端·设计模式·策略模式
金书世界2 小时前
使用PHP+html+MySQL实现用户的注册和登录(源码)
开发语言·mysql·php