**Java 篇-设计模式
设计原则:
开闭原则:对原代码不做修改,对扩展开放
单一原则
里氏替换原则
依赖倒置原则
接口隔离:
迪米特原则:最少知道原则,尽量降低类与类之间的耦合
单例模式:
(1)饿汉式
类加载到内存(Class.forName(''))后,就实例化一个单例,jvm保证线程安全
简单实用,推荐
缺点:不管用到与否,类装载时就完全实例化。
private static final SingleTon INSTANCE = new SingleTon ();
private SingleTon (){}
public static SingleTon getInstance(){return INSTANCE;}
(2)静态语句块
同法一
private static final SingleTon INSTANCE;
static{ INSTANCE = new SingleTon ();}
private SingleTon (){}
public static SingleTon getInstance(){
return INSTANCE;
}
(3)懒汉式
虽达到了按需初始化的目的,但线程不安全
private static SingleTon INSTANCE;
private SingleTon (){}
public static SingleTon getInstance(){
if(INSTANCE == null){
INSTANCE = new SingleTon();
}
return INSTANCE ;
}
**final 必须初始化**
(4)懒汉+锁
安全了,但效率下降
锁住的是当前类对象
public static synchronized SingleTon getInstance(){ }
(5)试图通过减少同步代码块方式提高效率,然后不行
当线程进入加锁前,另一个线程来了,为空先进入加锁了..new 对象,释放锁后,前者继续 也new 对象。
public static SingleTon getInstance(){
if(INSTANCE == null){
synchronized (SingleTon.class){
INSTANCE = new SingleTon();
}
return INSTANCE ;
}
}
(6) **双重校验+锁 推荐**
java 虚拟机内部执行时,对于汇编java 语言进行优化,语句重排。----一般不会优化。
无volatile 情况,并发时,实例对象时会出错:
**INSTANCE = new SingleTon();
1.menory=allocate() 分配内存
2.ctorInstance(memory) 初始化对象
3.s = memory 设置s指向刚分配的地址**
运行时,可能会重排序,从1.2.3排位1.3.2
==》线程A、B,A执行了1.3,未2,B来了,判断s 不为空,直接返回一个未初始化对象,就gg了。
==》**volatile:防止产生指令的重排序问题**
public static volatile SingleTon getInstance(){
if(INSTANCE == null){
synchronized (SingleTon.class){
if(INSTANCE == null){
INSTANCE = new SingleTon();
}
}
}
return INSTANCE ;
}
(7)静态内部类 推荐
JVM保证单例,和安全(static 值加载一次)
加载外部类时不会加载内部类,这样可实现懒加载
private static class SingleHolder{
private final static SingleTon INSTANCE =new SingleTon();
}
public static SingleTon getInstance(){
return SingleHolder.INSTANCE ;
}
(8)枚举 (Effective Java 中提出) 推荐
不仅可以解决线程同步,还可以防止反序列化(自动支持序列化机制),还安全。
==》序列化问题:java 的反射是可以通过 类.class文件 load 到内存,再new一个实例出来;实际中要设置变量;枚举单例不会被反序列化是因为枚举类无构造方法,只能得到 枚举值INSTANCE 。
public enum SingleTon{
INSTANCE;
public void m(){}
}
实际中可以spring 的 bean工厂来保证单例
策略模式
Strategy:Comparable 接口 --方法 compareTo()
策略:Comparator接口 compare() --可对功能进行扩展,不更新原代码情况下。
代理模式
常见于数据库连接池
设计连接池:
1.connection 容器 List \ Queue Set
2.连接池 是单例的,有初始化默认连接数 一般为10
3.方法 :获取连接 归还连接
==>接口本身没有归还连接操作
==>写一个类-,也实现connection 接口,持有jdbc的引用,实现一个 close方法-》称为代理类---**静态代理**
public class ConnectProxy implements Connection{}
**动态代理**
**基于JDK :目标对象是接口(Proxy内部实现决定的);由java内部的反射机制来实例化代理对象,并代理的调用委托类方法**
实例化代理类时,缓存有则取,无则创建;proxy生成新代理类继承proxy,实现InvocationHandler接口,该接口只有invoke方法,invoke对真是角色代理访问。
Proxy.newProxyInstance(被代理对象.class.getClassLoader(),new Class[] {被代理类接口.class},new 动态代理类实现(coon连接))
==》1.传入一个InvocationHandler实现类
2.生成接口的代理类的Class对象 getProxyClass0(loader,intfs)
3.根据代理类对象c1 获取构造器 getProxyConstructer(caller,loader,interfaces) 代理缓存池
4.根据构造器和InvocationHandler实现类,创建代理类实例
反射获取接口信息。(反射reflection:通过二进制字节码分析类的属性和方法)
asm:目前最广泛的二进制字节码的操作类库;30-50k;直接可操作字节码;用了asm -->动态语言。
mybatis 核心思想 jdk 动态代理:通过没有实现类的mapper 接口找到mapper映射器里的SQL语句执行。----》没有实现类的接口如何执行?--》MapperProxy 实现了InvocationHandler动态代理类
ps:Instrument java 自带;是java 文件loader 到内存的过程中拦截.class ,可以又自己的定制,相当于可以通过它直接修改二进制码,功能>asm ,但繁琐。
基于cglib: 目标是类;不能代理final 修饰的方法;基于继承被代理类生成代理子类,不用实现接口;底层是借助asm字节码技术
代理类是被代理类的子类,重写父类方法
pom.xml 需要添加。
被代理类无需实现接口;代理类实现MethodIntercepter接口,对intercepter调用获取被代理信息。
spring ioc aop(动态代理)
aop面向切面编程:记录日志、检验参数、检查权限、发送通知、事务
spring-config.xml 中配置,一个简单的方式 以注解方式:
<aop:aspectj-autoproxy> 并pom.xml中添加jar包配置,
其次被代理类添加@Aspect
工厂方法
任何可以产生对象的方法或类,都可以称之为工厂。
单例也是一种工厂。
有了new后,还要有工厂? 灵活控制生产过程;权限、修饰、日志...
形容词用interface 名词用abstract
方便产品的扩展--FactoryMethod;产品一族进行扩展---抽象工厂
spring IOC --bean工厂
观察者模式 Observer/Listener
Observer Listener Hook CallBack 都是观察者模式