• java设计模式初探



    java反射机制

    我们平常都是通过new一个类来实例化一个对象,但是我们同时可以通过反射机制来构建,并且动态获取类里面的信息 比如说构造函数,方法和属性。

    常用的代码像是这个:

    方法 功能
    Class<?> Class.forName("全类名") 加载该类对象,并且通过这个方法可以获得类的信息
    xxx.newInstance() 实例化一个对象,这个我一般和上面的代码一起用来实例化对象
    Class.forName("xx").getDeclaredxxx 获得该类的信息

    单例模式

    • 单利模式的共同点就是将构造函数私有化。

    饿汉式

    public class UserEntity {
    
        private String username;
    
        private static final  UserEntity user = new UserEntity();
    
        static {
            System.out.println("静态代码块");
        }
    
        private UserEntity() {
            System.out.println("默认构造函数");
        }
    
    
        {
            System.out.println("非静态代码块");
        }
    
    
        public static UserEntity getInstance(){
            return user;
        }
    
    
        public void setUsername(String username){
            this.username = username;
        }
    
        public String getUsername(){
            return username;
        }
    
    }
    
    
    • 通过对该类进行java反射可以知道,static代码块在Class.forName装载的时候开始执行,而实例化的时候非静态代码块和构造函数开始执行

    懒汉式

    • 实体类在需要的时候才创建。
    public class UserEntity {
    
        private String username;
    
        private static UserEntity user;
    
        static {
            System.out.println("静态代码块");
        }
    
        private UserEntity() {
            System.out.println("默认构造函数");
        }
    
    
        {
            System.out.println("非静态代码块");
        }
    
    	/*这里加锁保证线程安全*/
        public synchronized static UserEntity getInstance(){
            if(user == null){
                user = new UserEntity();
            }
            return user;
        }
    
    
        public void setUsername(String username){
            this.username = username;
        }
    
        public String getUsername(){
            return username;
        }
    
    }
    

    静态内部类

    public class UserEntity2 {
    
    
        private UserEntity2() {
        }
    
        public static class SingleInstance{
            private static final UserEntity2 user = new UserEntity2();
        }
    
    
        public static UserEntity2 getInstance(){
           return SingleInstance.user;
        }
    }
    

    枚举

    //使用枚举实现单例模式 优点:实现简单、枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞 缺点没有延迟加载
    public class User {
    	public static User getInstance() {
    		return SingletonDemo04.INSTANCE.getInstance();
    	}
    
    	private static enum SingletonDemo04 {
    		INSTANCE;
    		// 枚举元素为单例
    		private User user;
    
    		private SingletonDemo04() {
    			System.out.println("SingletonDemo04");
    			user = new User();
    		}
    
    		public User getInstance() {
    			return user;
    		}
    	}
    
    	public static void main(String[] args) {
    		User u1 = User.getInstance();
    		User u2 = User.getInstance();
    		System.out.println(u1 == u2);
    	}
    }
    
    
    

    双重检验锁

    可以看作是对懒汉式的一个改版

    public class SingletonDemo04 {
    	private SingletonDemo04 singletonDemo04;
    
    	private SingletonDemo04() {
    
    	}
    
    	public SingletonDemo04 getInstance() {
    		if (singletonDemo04 == null) {
    			synchronized (this) {
    				if (singletonDemo04 == null) {
    					singletonDemo04 = new SingletonDemo04();
    				}
    			}
    		}
    		return singletonDemo04;
    	}
    
    }
    

    单例模式的选择

    如果不需要延迟加载单例,可以使用枚举或者饿汉式,相对来说枚举性好于饿汉式。

    如果需要延迟加载,可以使用静态内部类或者懒汉式,相对来说静态内部类好于懒韩式。

    最好使用饿汉式

    工厂模式

    • 工厂模式将实例化的工作从客户手里夺了回来,Spring的依赖反转也是这个道理

    简单工厂模式

    • 简单工厂一般代码不会更改,拓展性差

    工厂方法模式

    • 工厂方法一般是如果产品非常多的情况下,派生出不同的工厂去实例化不同的产品。

    抽象工厂

    这里分清楚产品族和产品树的关联

    在下面的图中,两个产品有关联的实体形成了产品族,一个工厂只生产一个产品族。

    产品树可以理解为由一个接口派生出来的类。

    模板方法模式

    • 这个方法是平时用的蛮多的一个
    • 其实模板方法就是将子类都利用的方法在父类中写好。

    建造者模式

    • Builder 可以根据客户提交的参数自定义产品的零件来产生不同的产品,这也是建造者模式和工厂模式的一个很大的区别。

    建造者的应用场景

    • 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
    • JAVA 中的 StringBuilder。

    代理模式

    通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。SpringAOP就是代理模式

    静态代理

    静态代理一般都是将代码写死了,在项目中用的也很少,理解即可。

    动态代理

    静态代理有很大的缺陷,就是如果像让很多类都就行切面,不可能都去写进Proxy里面,这样动态代理就可以解决这个问题。

    JDK动态代理

    // 每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象 
    public class InvocationHandlerImpl implements InvocationHandler {
    	private Object target;// 这其实业务实现类对象,用来调用具体的业务方法
    	// 通过构造函数传入目标对象
    	public InvocationHandlerImpl(Object target) {
    		this.target = target;
    	}
    
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		Object result = null;
    		System.out.println("调用开始处理");
    		result = method.invoke(target, args);
    		System.out.println("调用结束处理");
    		return result;
    	}
    
    	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
    			IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    		// 被代理对象
    		IUserDao userDao = new UserDao();
    		InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao);
    		ClassLoader loader = userDao.getClass().getClassLoader();
    		Class<?>[] interfaces = userDao.getClass().getInterfaces();
    		// 主要装载器、一组接口及调用处理动态代理实例
    		IUserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
    		newProxyInstance.save();
    	}
    
    }
    

    CGLib动态代理

    需要asm-all和cglib的jar包

    public class CglibProxy implements MethodInterceptor {
    	private Object targetObject;
    	// 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
    	public Object getInstance(Object target) {
    		// 设置需要创建子类的类
    		this.targetObject = target;
    		Enhancer enhancer = new Enhancer();
    		enhancer.setSuperclass(target.getClass());
    		enhancer.setCallback(this);
    		return enhancer.create();
    	}
    
    	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    		System.out.println("开启事物");
    		Object result = proxy.invoke(targetObject, args);
    		System.out.println("关闭事物");
    		// 返回代理对象
    		return result;
    	}
    	public static void main(String[] args) {
    		CglibProxy cglibProxy = new CglibProxy();
    		UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDao());
    		userDao.save();
    	}
    }
    
    

    门面(外观)模式

    外观模式,其实就是将后面很复杂的方法封装成一个类里面,让客户直接调用封装类里面的方法即可。

    适配器模式

    将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。

    策略模式

    现实开发中如果我们由一个根据不同情况创建不同实体的情况下,无论是用if-else或者是swith实现,代码是不符合开闭原则的,也就是他的拓展性并不高。

    那么,策略模式,解决了这个问题。其实,他的代码是比之前多了不少,但是这样也同时隐藏后台的核心代码,只将Strategy接口交给了用户,保证了一定的安全性。

  • 相关阅读:
    HTTP 与 HTTPS 的区别
    cookie 和session 的区别详解
    IntelliJ远程调试教程
    selenium 自动化测试面试题及答案
    性能测试总结(一)---基础理论篇(转载)
    性能测试总结(二)---测试流程篇(转载)
    性能测试总结(三)--工具选型篇
    eclipse调试的基本意义
    控制反转(IOC)和依赖注入(DI)
    前端框架layui
  • 原文地址:https://www.cnblogs.com/adroitwolf/p/14309891.html
Copyright © 2020-2023  润新知