设计模式

一、代理模式

使用代理类对真实对象进行代理,包括真实对象方法的调用、功能的扩展等。访问的时候也只能访问到代理对象,既保护了真实对象同时可以在原始对象上进行扩展。类似于中介在卖家和买家之间的角色。

代理模式的角色主要有:抽象角色、真实角色、代理角色

1.静态代理

以张三到二手平台售卖二手电脑为例,张三为真实角色,二手平台为代理角色

抽象角色:

public interface User {
void sell();//购买方法
}

真实角色:

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserImpl implements User{ private String name="张三";
private String thing="二手电脑"; @Override
public void sell() {
System.out.println(name+"要卖掉"+thing);
}
}

代理角色:

@Component
public class UserProxy implements User {
UserImpl user; @Override
public void sell() {
before();
user.sell();
after();
}
//扩展
public void before(){
System.out.println("包装了"+user.getThing());
}
public void after(){
System.out.println("售后服务");
}
}

测试:

@Component
public class StaticProxyTest {
public static void main(String[] args) {
new UserProxy(new UserImpl()).sell();
}
}

看起来似乎很简单,只是加了一层代理类就实现了扩展功能,但实际上维护时非常困难的。如果用户此时新增了需求,要在平台上买东西。那么直接带来了大量的代码工作,效率很低。也就产生了动态代理。

2.动态代理

和静态代理不同的是,动态代理的代理类是spring为我们生成的。相当于mybatisplus和mybatis的区别。

代理类生成工具类

public class DynamicProxy {
/*jdk动态代理
代理类需要是接口实现类impl.getClass().getInterfaces(),接收代理实例也是用接口来接收
通过反射Instance+拦截器Handler实现
jdk自带的代理支持
*/
public static Object jdkProxy(final Object impl){
Object proxyInstance = Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass()
.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke=null;
System.out.println("商品包装");
invoke = method.invoke(impl, args);
System.out.println("售后服务");
return invoke;
}
});
return proxyInstance;
} /*CGlib动态代理
通过对类继承来实现,无需接口实现
第三方工具,基于ASM实现
*/
public static Object CGlibProxy(final Object impl){
Object proxyInstance = Enhancer.create(impl.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object invoke = null;
System.out.println("商品包装");
invoke = method.invoke(impl, objects);
System.out.println("售后服务");
return invoke;
}
});
return proxyInstance;
} }

又或者可以实现对应的接口,以InvocationHandler举例

public class DynamicProxy implements InvocationHandler {
private User user; public Object getProxyInstance(User user){
this.user=user;
return Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
System.out.println("商品包装");
invoke = method.invoke(user, args);
System.out.println("售后服务");
return invoke;
}
}//实际使用中只需要调用getProxyInstance方法,丢入一个原始类即可

使用:

public class DynamicProxyTest {
public static void main(String[] args) {
UserImpl user = new UserImpl();
User o = (User)DynamicProxy.jdkProxy(user);
o.sell();
// UserImpl o1 = (UserImpl)DynamicProxy.CGlibProxy(user);
// o1.sell();
}
}

3.Spring AOP

springaop便是动态代理实践的一个典例,不改变方法原有的代码,实现对方法功能的增强,使用aop之前,对aop相关的概念是一定要了解清楚的。

(1)aop相关概念

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 接入点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切入点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的抽象集合,一般以类的形式呈现。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
(2)springaop注解开发

由于目前来说,注解开发是最简单快捷的,这里只介绍注解开发,我们只需要知道底层是用动态代理实现的即可。

  • 创建切面类和通知

    只需要在类上添加@Aspect注解

    @Aspect
    public class MyAspect {
    public void before(){
    System.out.println("方法执行前");
    }
    public void after(){
    System.out.println("方法执行后");
    }
    }
  • 创建并注入切点

    @Aspect
    public class MyAspect {
    //表示将com.amlia.service包下的所有的类的所有方法(任何参数)定义为切点
    @Pointcut("execution(* com.amlia.service.*.*(..))")
    public void pointCut(){}
    @Before("pointCut()")
    public void before(){
    System.out.println("方法执行前");
    }
    //也可以直接在通知上面定义切点
    @After("execution(* com.amlia.service.*.*(..))")
    public void after(){
    System.out.println("方法执行后");
    }
    }
  • 除了before和after类型的通知外,还有其他类型

    @Before:方法执行前通知

    @After:方法执行后通知

    @Around:方法环绕通知

    @AfterReturning:方法返回后通知

    @AfterThrowing:方法错误抛出之后

    可以测试他们的执行顺序:

(3)aop的应用
  • 打印日志(方法执行前后打印参数方法名返回值或者调用关系等信息)

    日志级别:

    • OFF 关闭日志
    • FATAL 较严重的问题,高于ERROR
    • ERROR 打印错误信息
    • WARN 打印告警信息
    • INFO 打印日常信息
    • DEBUG 打印调试信息
    • TRACE 打印追踪信息
    • ALL 打印所有信息
  • 性能检测(方法执行前和方法执行后分别进行时间截取求差值)

  • 事务控制(抛出错误后进行事务回滚)

  • 权限控制(方法执行前检测用户是否有权限)

二、单例模式

单例模式顾名思义就是该类只能有一个实例,而且是被类自己创建的。外界不能访问该类的构造方法,因为他是私有的。这种模式为了解决单个类频繁的创建和销毁的情况或者说是某种单个实例的场景,比如只能有一个中国实例,并且很多框架底层都使用了单例模式,比如bean的生命周期中就有singleton单例。

单例模式有很多实现方式,为了适应不同种情况:

1.懒汉模式

客人点单了厨师才开始做菜,线程不安全,如果需要线程安全,单体架构下,在方法上加synchronize关键字即可,多体架构下,方法体内加分布式锁。

public class Singleton {
private static Singleton instance;
private Singleton (){}//构造方法私有 public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();//需要时加载——懒式加载
}
return instance;
}
}

2.饿汉模式

厨师提前做好菜,客人点了直接上菜。由于类加载过程中是阻塞等待机制,所以是线程安全的。缺点是产生了大量的"垃圾"对象,比较占用资源。

public class Singleton {
private static Singleton instance = new Singleton();//加载时初始化
private Singleton (){}//构造方法私有 public static Singleton getInstance() {
return instance;
}
}

3.双重校验的单例模式

大部分情况下,懒汉饿汉已经满足了。但是如果要求多线程下安全且高性能,那么还有一个较为复杂的模式

public class Singleton {
//volatile防止初始化指令重排,导致其他线程误以为初始化完成,空指针
private volatile static Singleton singleton;排
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {//提升性能
synchronized (Singleton.class) {
if (singleton == null) {//防止阻塞等待下实例化已经完成的情况
singleton = new Singleton();
}
}
}
return singleton;
}
}

4.静态内部类单例模式

这种方法同样利用了类加载机制的线程安全,但是巧妙的规避了资源的浪费。他利用内部类静态域的加载特性(使用时加载)达到了懒汉饿汉结合的效果。

public class Singleton {
private static class SingletonHolder {
//静态内部类的静态域
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

Java进阶篇——设计模式的更多相关文章

  1. Java进阶篇 设计模式之十四 ----- 总结篇

    前言 本篇是讲述之前学习设计模式的一个总结篇,其目的是为了对这些设计模式的进行一个提炼总结,能够通过查看看此篇就可以理解一些设计模式的核心思想. 设计模式简介 什么是设计模式 设计模式是一套被反复使用 ...

  2. Java进阶篇设计模式之十三 ---- 观察者模式和空对象模式

    前言 在上一篇中我们学习了行为型模式的备忘录模式(Memento Pattern)和状态模式(Memento Pattern).本篇则来学习下行为型模式的最后两个模式,观察者模式(Observer P ...

  3. Java进阶篇设计模式之十一 ---- 策略模式和模板方法模式

    前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...

  4. Java进阶篇设计模式之十 ---- 访问者模式和中介者模式

    前言 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern).本篇则来学习下行为型模式的两个模式,访问者模式(Visito ...

  5. Java进阶篇设计模式之九----- 解释器模式和迭代器模式

    前言 在上一篇中我们学习了行为型模式的责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern).本篇则来学习下行为型模式的两个模式, 解 ...

  6. Java进阶篇设计模式之八 ----- 责任链模式和命令模式

    前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command ...

  7. Java进阶篇设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  8. Java进阶篇设计模式之二 ----- 工厂模式

    前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...

  9. Java进阶篇设计模式之三 ----- 建造者模式和原型模式

    前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...

  10. Java进阶篇设计模式之十二 ---- 备忘录模式和状态模式

    前言 在上一篇中我们学习了行为型模式的策略模式(Strategy Pattern)和模板模式(Template Pattern).本篇则来学习下行为型模式的两个模式,备忘录模式(Memento Pat ...

随机推荐

  1. F118校准(一)-- 安装CA310驱动程序及SDK

    1. 准备工作 下载Ca310_drv.zip文件并解压,备用. http://www.xk-image.com/download/blog/0001_F118校准/Ca310_drv.zip 准备好 ...

  2. 缺省源&一些常用的码头

    #include <bits/stdc++.h> #define N 1000010 #define M 2000010 #define pii pair<int,int> # ...

  3. FastApi学习1

    先写路由文件: 其次通过ORM操作数据库相关:

  4. 基于Spring的发布订阅模式 EventListener

    基于Spring的发布订阅模式 在我们使用spring开发应用时,经常会碰到要去解耦合一些依赖调用,比如我们在做代码的发布流程中,需要去通知相关的测试,开发人员关注发布中的错误信息.而且通知这个操作又 ...

  5. 谈软件-专家谈C/C++重构的操作与思路

    1.Refactoring: 对软件内部结构的一种调整,目的是不该被软件的可观察行为的前提上,提高其可理解性,降低其修改成本. 2.代码坏味道 2.1.不易复用 2.2.不易理解 2.3.存在冗余 3 ...

  6. 区分mbr与gpt分区

    查看分区类型 [root@localhost ~]# parted -l|egrep 'dev/|Part' Warning: Unable to open /dev/sr0 read-write ( ...

  7. vue-element Form表单验证没错却一直提示错误

    在使用element-UI 的表单时,发生一个验证错误,已输入值但验证的时候却提示没有输入 修改前 <el-form-item>中的prop绑定的是cus_name,而item里面的控件绑 ...

  8. LayuI 动态下拉框和动态设置选中

    动态下拉框 //下拉框异步加载 function asyncSelect(thisId, grade, selectNodeName) { $("#" + selectNodeNa ...

  9. vivo浏览器的神奇操作

    关闭 root 权限也就罢了,你还搞这种操作 看到那个源文件了吗? 只有点击源文件下载的才是 官方提供的安装包, 而你首先看到的下载,点击后会下载vivo 应用商店的安装包. 那么这两种安装包有什么区 ...

  10. 第2-4-9章 规则引擎Drools实战(2)-信用卡申请

    目录 9.2 信用卡申请 9.2.1 计算规则 9.2.2 实现步骤 9.2 信用卡申请 全套代码及资料全部完整提供,点此处下载 本小节我们需要通过Drools规则引擎来根据规则进行申请人的合法性检查 ...