设计模式(知识点记录)

本文深入探讨了Java的反射机制,包括如何获取类信息、创建对象以及防止反射攻击的方法。此外,还详细阐述了多种设计模式,如单例模式的五种实现方式、工厂模式的分类以及代理模式的应用。同时,提到了建造者模式、模板方法模式、适配器模式、外观模式和原型模式的关键概念和使用场景。
摘要由CSDN通过智能技术生成

一、反射机制

1、什么是反射机制

        正在运行,动态获取类的信息。

2、反射机制的作用

        a.反编译:.class-->.java;

        b.使用反射机制获取类的属性、方法、实例化对象;

        c.不使用new 可以获取对象

3、反射机制创建对象

        //使用java的反射机制创建对象 类的完整路径

        Class<?> class=Class.forName("com.a.User");

        //使用反射 创建对象

        User user=(User)class.newInstance();

        //调用有参构造函数

        Constructor<?> constructor=class.getConstructor(String.class);

        User user2=(User)constructor.newInstance("张三");

4、怎么防止被反射

        a       

5、反射机制应用场景

        a. jdbc 连接

        b. SpringIOC底层使用反射机制+DOM4J

        c.框架Hibernate、mybatis 

二、设计模式

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

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

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

三、单例设计模式

1、什么是单例设计模式?

        保证在一个jvm中,只能存在一个实例,保证对象唯一性。

2、单例设计模式应用场景?

        servlet、spring、sruts2、springmvc、连接池、线程池、枚举、常用

3、单例的好处与缺点

        好处:节约内存,重复利用,方便管理

        缺点:线程安全问题

4、单例创建方式

        a.饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
       

public class User01 {
    //类初始化时就会创建对象,调用效率高,但不调用时会浪费内存
    private static final User01 user=new User01();

    //私有化构造函数
    private User01(){}

    //定义获取对象静态方法
    public static User01 getInstance(){
        return user;
    }

    //调用 获取对象
    public static void main(String[] args){
        User01 user01=User01.getInstance();
    }


}

        b.懒汉式:类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。

public class User02{
    //类初始化的时候 不生成对象
    private static User02 user02;

    //私有化构造函数
    private User02(){}

    //在调用时,先判断是否为空对象,若为空再生成对象。但此处会有线程安全问题,如是多线程可能会创建多个对象。所以最好加上synchronized
    public static synchronized User02 getInstance(){
        if(null==user02){
            user02=new User02();
        }
        return user02;
    }

}

        c.静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全。

public class User03{
    private User03(){}

    public static class SingletonUserInstance{
        private static final User03 user03=new User03();
    }

    public static User03 getInstance(){
        return new SingletonUserInstance.user03;
    }

}

        d.枚举单例:使用枚举实现单例模式 优点:实现简单,调用效率高,枚举本身就是单例,由jvm从根本上提供保障 避免通过反射和反序列化的漏洞,缺点:没有延迟加载。

public class User04{
    private User04(){}

    public static User04 getInstance(){
        return SingletonUserEnum.INSTANCE.getInstance();
    }

    //枚举本来就是单例
    static enum SingletonUserEnum{
        INSTANCE;
        private User04 user04;
        //此方法只会执行一次
        private SingletonUserEnum(){
            user04=new User04();
        }

        public User04 getInstance(){
            return this.user04;
        }

    }

}

        e.双重检测锁方式:

public class User05{
    private static volatile User05 user05;
    private User05(){}

    public static getInstance(){
        if(null==user05){
            synchronized(this){
                if(null==user05){
                    user05=new User05();
                }
                
            }
        }
        return user05;
    }


}

四、工厂模式

1、简单工厂(用来生产同一等级结构中的任意产品。不支持拓展增加产品)

        简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。

//car interface
public interface Car{
    void run();
}


//Car object 1
public class BydCar implements Car{
    public void run(){
        System.out.println("比亚迪");
    }
}

//Car object 2
public class JiliCar implements Car{
    public void run(){
        System.out.println("吉利");
    }
}

//Car Factory
public class CarFactory{
    public static createCar(String name){
        if("比亚迪".equals(name)){
            return new BydCar();
        }
        if("吉利".equals(name)){
            return new JiliCar();
        }
        return null;
    }
}

//client
public class Client{
    public static void main(String[] args){
        Car byd=CarFactory.createCard("比亚迪");
    }
}

2、工厂方法设计模式(用来生产同一等级结构中的固定产品。支持拓展增加产品)

        工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

//car factory interface
public interface CarFactory{
    Car createCar(String name);
}

public class BydCaryFactory implements CarFactory{
    public Car createCar(String name){
        return new BydCar();
    }
}


public class JiliCaryFactory implements CarFactory{
    public Car createCar(String name){
        return new JiliCar();
    }
}

3、抽象工厂(用来生产不同产品族的全部产品。不支持拓展增加产品;支持增加产品族)

        抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。

五、代理设计模式

1、什么是代理模式

        通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用之前或调用后处理。既(AOP微实现)  ,AOP核心技术面向切面编程。

2、代理模式应用场景

        SpringAOP,事务原理,日志打印,权限控制,远程调用,安全代理,可以隐蔽真实角色。

3、静态代理

        由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

public interface UserDao{
    void save();
}

public class UserDaoImpl implements UserDao{
    public void save(){
        System.out.println("保存.....");
    }
}

//代理类
public class UserDaoProxy implements UserDao{
    private UserDaoImpl userDao;
    public UserDaoProxy(UserDaoImpl userDao){
        this.userDao=userDao;
    }

    public void save(){
        System.out.println("开启事务.....");
        userDao.save();
        System.out.println("提交事务.....");
    }
}

4、动态代理

        a.什么是动态代理

        代理对象,不需要实现接口。

        代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。

        动态代理也叫做:JDK代理,接口代理。

        b.实现方式:JDK代理

        通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);

        通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});

        通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

        通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

//每次生成动态代理类对象时,实现了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 {
		// 被代理对象
		UserDao userDao = new UserDao();
		InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao);
		ClassLoader loader = userDao.getClass().getClassLoader();
		Class<?>[] interfaces = userDao.getClass().getInterfaces();
		// 主要装载器、一组接口及调用处理动态代理实例
		UserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
		newProxyInstance.save();
	}

}

c.CGLIB代理

        不要求委托类实现接口,底层使用ASM字节码生成框架生成代理类的字节码。

//引用包
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>


public class CglibProxy implements MethodInterceptor{
    private Object target;
    public Object getInstance(Object target){
        this.target=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){
        System.out.println("开启事务");
        Object invoke=proxy.invoke(obj,arges);
        System.out.println("提交事务");
        return invoke;
    }

    public static void main(String[] args){
        CglibProxy proxy=new CglibProxy();
        UserDaoImpl userDao=(UserDaoImpl)proxy.getInstance(new UserDaoImpl());
        userDao.add();
    }

d.CGLIB动态代理与JDK动态代理的区别

        JDK代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。CGLIB代理 是利用asm开源包,对代理对象类的class文件加载进来,通过修改字节码生成子类来处理。

        JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。

        CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。

五、建造者模式

        将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。就是将各种产品集中起来进行管理,用来创建复合对象。使用场景:需要生成的对象具有复杂的内部结构。需要生成的对象内部属性本身相互依赖。与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

六、模板方法模式

        处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用模板方法模式,将这个节点的代码实现转移给子类完成。即:处理步骤在父类中定义好,具体的实现延迟到子类中定义。

        应用场景:数据库访问的封装、Junit单元测试、servlet中关于doGet/doPost方法的调用、Hibernate中模板程序、spring中JDBCTemplate,HibernateTemplate等等。

七、适配器模式

        适配器模式一般是用来解决兼容的问题。分为类适配器、对象适配器、接口适配器,类适配器方式采用继承方式,对象适配方式使用构造函数传递。

使用场景:

1、我们在使用第三方的类库,或者说第三方的API的时候,我们通过适配器转换来满足现有系统的使用需求。

 2、我们的旧系统与新系统进行集成的时候,我们发现旧系统的数据无法满足新系统的需求,那么这个时候,我们可能需要适配器,完成调用需求。

 3、我们在使用不同数据库之间进行数据同步。(我这里只是分析的是通过程序来说实现的时候的情况。还有其他的很多种方式[数据库同步])。

4、OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变为字节流的输出对象。InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即:将一个字节流的输入对象变为字符流的输入对象。

八、外观模式

        隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

        使用场景:在Spring 中使用最广泛。

九、原型模式

        原型模式是一个创建型的模式。原型二字表明了改模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。

        原型模式分为浅复制和深复制,浅复制仅是复制基本类型的数据,而引用类型数据,只是复制内存地址。深复制指的是在内存开辟一块新的内存地址用于存放复制的对象。

        使用场景:

        (1) 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。 

        (2) 通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。 

        (3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值