A098_常用设计模式

1.内容介绍

1. 常用设计模式;(掌握)

2.设计模式

2.1.什么是设计模式

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

设计模式就是前人写代码的有些优秀经验,总结下来了。我们把它拿到我们项目中使用,让我们的代码更加优美,高效,可读性高。

2.2.设计模式分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

2.3.常见的设计模式
2.3.1.单例

一个类只有一个实例。工具类,spring中对象默认都是单例。
1)饿汉模式
 ①构造方法私有化
 ②创建一个对象
 ③提供方法访问
2)懒汉模式
 ①应用程序在第一次调用方法获取单利模式对象的时候创建对象
 ②线程安全
在这里插入图片描述
3)枚举

2.3.2.工厂

工厂顾名思义就是创建产品,工厂分为三种:简单工厂,工厂方法,抽象工厂。该模式用于封装和管理对象的创建,是一种创建型模式。本文从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和利弊。

1)简单工厂
该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:
在这里插入图片描述

public class PhoneFactory {
    public Phone makePhone(String phoneType) {
        if(phoneType.equalsIgnoreCase("MiPhone")){
            return new MiPhone();
        }
        else if(phoneType.equalsIgnoreCase("iPhone")) {
            return new IPhone();
        }
        return null;
    }
}

2)工厂方法
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,其UML类图如下:
在这里插入图片描述

public class Demo {
    public static void main(String[] arg) {
        AbstractFactory miFactory = new XiaoMiFactory();
        AbstractFactory appleFactory = new AppleFactory();
        miFactory.makePhone();            // make xiaomi phone!
        appleFactory.makePhone();        // make iphone!
    }
}

3)抽象工厂
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品Phone(AbstractProduct),如果要生成另一种产品PC,应该怎么表示呢?

最简单的方式是把2中介绍的工厂方法模式完全复制一份,不过这次生产的是PC。但同时也就意味着我们要完全复制和修改Phone生产管理的所有代码,显然这是一个笨办法,并不利于扩展和维护。

抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
在这里插入图片描述
Spring中应用:
IOC:简单工厂+Map缓存单例+反射

2.3.3.代理
1)概念

所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。
这样我们可以在代理调用被代理对象之前,之后,报错加入自己的逻辑。
在这里插入图片描述

2)静态代理

代理分为动态代理与静态代理。我们先从简单的静态代理开始研究。

public interface Subject {
    void visit();
}

public class RealSubject implements Subject {

    private String name = "byhieg";
    @Override
    public void visit() {
        System.out.println(name);
    }
}

public class ProxySubject implements Subject{

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        //做事情
        subject.visit();
       //做事情
    }
}
public class Client {

    public static void main(String[] args) {

        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
    }
}
3)动态代理

动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。

Java1.3就提供了动态代理,让咱们可以在代码运行期去实现一个接口的代理实例。这个功能在刚出来时,几乎没有太大实际用途,但是后来发现,它简直就是为实现AOP量身打造。

但是大家注意了,jdk的动态代理只允许完成有接口的代理,但是在我们开发的很多时候,可能还是会遇到去代理没有接口的类(创建的代理对象就是这个类的子类),比如咱们学习的Hibernate中的延时加载就是使用的这种方式。

那么Spring是怎么解决这个问题的呢?

Spring使用两种方式来完成动态代理:

如果代理的类有接口,使用JDK的动态代理模式,如果代理的类没有接口,使用CGLIB的动态代理模式。 所以,现在咱们要开始来学习一下怎么使用这两种模式来完成动态代理。

  • ①JDK动态代理
    注:JDK动态代理只能代理有接口的类
    ①.准备条件
    保留静态代理的结构(将代理类删除掉)
    在这里插入图片描述
    下面是完成JDK代理的主要类:
    java.lang.reflect.Proxy (可以到jdk文档中找到这个类)
    java.lang.reflect.InvocationHandler:代理调用处理程序的接口

  • ②.实现代码

创建JDKProxy类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * InvocationHandler:是代理实例的调用处理程序 实现的接口。 
 */
public class JdkProxy implements InvocationHandler{
	//定义真实主题角色:目标对象
	private Object targetObject;
	//传入事务管理器
	private TxManager txManager;
	public JdkProxy(Object targetObject,TxManager txManager) {
		this.targetObject = targetObject;
		this.txManager = txManager;
	}
	
	/**
	 * proxy:经过jdk的代理对象(基本上没有作用)
	 * method:实际执行的方法
	 * args:方法中的参数
	 */
	@Override
	public Object invoke(Object targetObject, Method method, Object[] args) throws Throwable {
		Object result = null; //返回的结果
		try {
			txManager.begin();
			result = method.invoke(targetObject, args); //执行直接对象的方法
			txManager.commit();
		} catch (Exception e) {
			txManager.rollback();
			e.printStackTrace();
		}finally{
			txManager.close();
		}
		return result;
	}
	
	/**
	 * 创建一个代理对象
	 * @return
	 */
	public Object createProxy(){
		return Proxy.newProxyInstance(
				this.getClass().getClassLoader(),  //类加载器,只要拿到一个即可
				targetObject.getClass().getInterfaces() , //实现类的接口集合(因为一个类可以实现多个接口)
				this //代理实例的调用处理程序(InvocationHandler的实现类)
			);
	}
}

测试功能:

@Test
public void testProxy() throws Exception {
	User user = new User();
	//真实主题角色对象
	IEmployeeService employeeService = new EmployeeServiceImpl();
	//事务管理器
	TxManager txManager = new TxManager();
	//创建咱们自定义的一个处理代理功能类(这个类中我们加了一个方法可以直接创建代理对象)
	JdkProxy jdkProxy = new JdkProxy(employeeService,txManager);
	//获取代理对象
	IEmployeeService proxy = (IEmployeeService)jdkProxy.createProxy();
	proxy.save(user);
}

②CGLIB动态代理
Cglib类似于javassist-3.18.1-GA.jar功能字节码增强,
原来Hibernate3.2之前就是使用cglib来进行字节码增强

①.下面是完成CGLIB的类:
org.springframework.cglib.proxy.Enhancer; 增强器
org.springframework.cglib.proxy.MethodInterceptor; 方法切面(代理实例处理方法功能的接口)
org.springframework.cglib.proxy.MethodProxy;

②.CGLIB的实现代码
CGLIBProxy类代码:

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor{

	//定义参数,接收真实的目标对象
	private Object targetObject;
	//事务对象
	private TxManager txManager;
	
	public CglibProxy(Object targetObject,TxManager txManager) {
		this.targetObject = targetObject;
		this.txManager = txManager;
	}
	
	/**
	 * proxyObject:CGLIB代理后的对象,一般不用
	 * method:真实对象的方法
	 * args:方法的参数
	 * methodProxy:CGLIB代理后的方法,一般不用
	 */
	@Override
	public Object intercept(Object proxyObject, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {
		Object result = null; //返回的结果
		try {
			txManager.begin();
			result = method.invoke(targetObject, args); //执行直接对象的方法
			txManager.commit();
		} catch (Exception e) {
			txManager.rollback();
			e.printStackTrace();
		}finally{
			txManager.close();
		}
		return result;
	}
	
	/**
	 * 创建一个代理对象
	 * @return
	 */
	public Object createProxy(){
		//创建增强器
		Enhancer enhancer = new Enhancer();
		//创建的代理就是咱们真实目标对象的子类
		enhancer.setSuperclass(targetObject.getClass());
		//MethodInterceptor就是一个Callback回调
		enhancer.setCallback(this);
		//创建一个代理对象并返回
		return enhancer.create();
	} 
}

测试代码

@Test
	public void testProxy() throws Exception {
		User user = new User();
		//真实主题角色对象
		EmployeeServiceImpl employeeService = new EmployeeServiceImpl();
		//事务管理器
		TxManager txManager = new TxManager();
		//创建Cglib代理对象
		CglibProxy cglibProxy = new CglibProxy(employeeService, txManager);
		//拿到代理对象
		EmployeeServiceImpl proxy = (EmployeeServiceImpl)cglibProxy.createProxy();
		proxy.save(user);
	}

Spring使用JDK与CGLIB两种动态代理

  • JDK动态代理:
    有接口的类使用JDK的动态代理(JDK动态代理不支持没有接口的类)
    如果有n个接口,必然有n个实现,只用写1个代理类JDKProxy就可以对所有有接口进行处理
    如果有代理主题角色存在,必须修改调用方才能实现代理

  • CGLIB动态代理:
    没有接口的类使用CGLIB动态代理(类有没有接口都可以支持)
    只用写1个代理类CglibProxy就可以对所有没有接口的不能是final类都进行处理
    如果有代理主题角色存在,必须修改调用方才能实现代理

2.3.4.模板

先定义一个操作中的算法骨架,而将算法的某一个或者某些步骤的具体实现延迟到了子类中来实现,使得子类可以在不修改当前算法的结构情况下,重新定义当前算法的某些特定步骤

角色:
抽象的基类

实现某些具体步骤的子类

关键代码:公共的代码在基类中实现(如:烧水、倒入杯中、送个客人这三个步骤就在基类hotdrink中实现的)

其他步骤在具体子类中实现(如:是泡茶还是泡咖啡粉就是在具体的子类中实现的)

JdbcTemplate ElasticSearchTemplate
在这里插入图片描述
在这里插入图片描述

2.3.5.其他
2.4.小结
1)你给说一下设计模式
   前人总结好的一些开发经验,可以拿过来在项目中使用,让我们的代码更加优美,高效,可读性高。
    分为三种:构造(单例,工厂),结构(代理),行为(模板)
2)你用过哪些设计模式
	我只用过单例,一个工具类都能使用单例,我是通过枚举的方式构造单例。。。。。。
	那工厂。。。。
3)Spring底层怎么实现
4)Spring ioc怎么实现
5)Spring aop怎么实现

3. 课程总结

3.1.重点
3.2.难点
3.3.如何掌握?

1.多多理解
2.学会看说明手册

3.4.排错技巧(技巧)

1…
2…

4.课后练习

1.总结
2.课堂作业

5.面试题

简单说一下单例模式?
    单例模式是一种创建型设计模式,一个类只能有一个实例。一般工厂类是单例,工具也是单例。。。。
    单例模式常见的有四种设计模式: 
        饿汉 懒汉简单加锁 懒汉双重判断加锁 枚举
    我常用的是枚举
Spring的两大核心??项目中怎么用spring
   Ioc
   Aop

Ioc底层原理
Aop底层原理

6.扩展知识或课外阅读推荐(可选)

6.1.扩展知识
6.2.课外阅读

微服务那点儿事情
https://blog.csdn.net/w05980598/article/details/79007194/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring常用设计模式包括装饰器模式、策略模式等。装饰器模式在Spring中被用于实现增强对象的功能,比如通过动态代理和AspectJ实现的环绕通知。这种模式通过装饰器来对对象进行功能增强。\[1\]而策略模式在Spring中被用于实现Bean的后置处理,通过在不同的时机调用不同的策略方法来对Bean进行处理。\[2\]这种模式将一组策略算法封装起来,外部客户端根据不同的条件选择不同的策略算法来解决问题。\[3\]除了这两种常用设计模式,Spring还运用了许多其他经典的设计模式,这些模式为Spring提供了良好的架构和扩展性,也为我们在实际开发中提供了更多的思路和方案。 #### 引用[.reference_title] - *1* *2* [【spring里面都用到了哪些设计模式】](https://blog.csdn.net/qq_43116031/article/details/129254736)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Spring中所使用的设计模式](https://blog.csdn.net/a745233700/article/details/112598471)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值