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);
}
}