JAVA设计模式笔记

**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()   --可对功能进行扩展,不更新原代码情况下。

JAVA设计模式笔记_第1张图片代理模式

常见于数据库连接池
	设计连接池:
	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连接))

JAVA设计模式笔记_第2张图片

			==》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 中配置,一个简单的方式   以注解方式:
	 并pom.xml中添加jar包配置,
	其次被代理类添加@Aspect 

工厂方法

任何可以产生对象的方法或类,都可以称之为工厂。
单例也是一种工厂。
有了new后,还要有工厂? 灵活控制生产过程;权限、修饰、日志...

形容词用interface  名词用abstract
方便产品的扩展--FactoryMethod;产品一族进行扩展---抽象工厂
spring IOC  --bean工厂

观察者模式 Observer/Listener
JAVA设计模式笔记_第3张图片

Observer  Listener Hook  CallBack  都是观察者模式

你可能感兴趣的:(设计模式,java,设计模式)