Java学习53天--装饰者设计模式,动态代理设计模式,自定义连接池,注解

一,装饰者设计模式

  • 1,定义装饰类(增强类)实现和被装饰类(被增强类)相同的接口
  • 2,在装饰类中声明被装饰类的引用
  • 3,在装饰类的方法中,使用被装饰调用原方法
package t1.example.util;

import t1.example.dao.UserDao;

public class UserDaoWrapper implements UserDao {

    private UserDao userDao;

    public UserDaoWrapper(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        System.out.println("权限校验");
        this.userDao .addUser();
        System.out.println("日志记录");
    }

    @Override
    public void deleteUser() {
        userDao.deleteUser();
    }

    @Override
    public void updateUser() {
        userDao.updateUser();
    }

    @Override
    public void SelectUser() {
        userDao.SelectUser();
    }
}

  • 作用
    • 在不侵入被装饰类源码的前提下,增强某个功能!
  • 特点
    • 不能控制被装饰类对象
  • 缺点
    • 需要重写接口中的所有方法,破坏了单一职责原则

二,Proxy动态代理
基于接口的方法增强
方式一:定义类实现InvocationHandler接口增强addUser方法

package t1.example.demo;

import t1.example.dao.UserDao;
import t1.example.dao.UserDaoImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理模式
 * 增强方法
 * Proxy类中的newProxyInstance方法
 */
public class Demo03 {
    public static void main(String[] args) {
        //ClassLosder loader:被代理类对应的类加载器
        //Class<?>[] interfacers:被代理类所实现的接口
        //InvocationHandler h:一个用以增强代理类的处理器
        UserDao userDao = new UserDaoImpl();
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                new MyInvocationHandler(userDao));
        userDaoProxy.addUser();
        userDaoProxy.SelectUser();
    }
}

/**
 * 相当于代理类增强器,用以增强代理类
 */
class MyInvocationHandler implements InvocationHandler{
    //声明一个被代理类的引用
    private UserDao userDao;

    public MyInvocationHandler(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //Method method:被代理类的原方法
        //Object[] args:被代理类方法的实际参数
        String methodName = method.getName();
        Object returnValue = null;
        if("addUser".equals(methodName)){
            //只有addUser需要增强
            System.out.println("权限校验");
            returnValue = method.invoke(userDao, args);
            System.out.println("日志记录");
        }else{
            //其他方法不增强
            method.invoke(userDao, args);
        }

        return returnValue;
    }
}

方式二:使用InvocationHandler接口的匿名内部类对象

package t1.example.demo;

import t1.example.dao.UserDao;
import t1.example.dao.UserDaoImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Demo04 {
    /**
     * 动态代理模式
     */
    public static void main(String[] args) {
        UserDao userDao = new UserDaoImpl();
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
                userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String methodName = method.getName();
                        Object returnValue = null;
                        if("addUser".equals(methodName)){
                            //只有addUser需要增强
                            System.out.println("权限校验");
                            returnValue = method.invoke(userDao, args);
                            System.out.println("日志记录");
                        }else{
                            //其他方法不增强
                            method.invoke(userDao, args);
                        }

                        return returnValue;
                    }
                });
        userDaoProxy.addUser();
        userDaoProxy.SelectUser();

    }
}

优点:不需要重写接口所有的方法!

三,连接池概念
在不使用连接池的情况下, 如果有100个用户要操作数据库,对应要创建100个连接对象,操作数据库完毕,还需要销毁100个连接对象,创建连接和销毁连接是非常浪费系统性能!
如果使用连接池,连接的创建,只在连接池初始化时才进行,当用户要操作数据库时,只需要从连接池中取出已经创建好的连接对象即可,操作数据库完毕,不需要销毁连接,只需将连接对象归还到连接池
总结
连接池提高了操作数据库的性能!

四,自定义连接池基础版

  • 初始化时,创建一些连接对象,并存储到LinkedList(增删快查询慢)集合中
  • 从连接池中取出连接
  • 把连接归还连接池
package t1.example.util;

//自定义连接池

import java.sql.Connection;
import java.util.LinkedList;

public class MyDataSourse {
    int initPoolSize = 3;

    LinkedList<Connection> connections = new LinkedList<>();

    //当连接池初始化时,创建一些连接,并存储起来
    public MyDataSourse() {
        creatConnections();
    }

    public void creatConnections(){
        for (int i = 0;i<initPoolSize;i++){
            try {
                Connection connection = JDBCUtils.getConnection();
                connections.add(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public Connection getConnection(){
        if(connections.size()==0||connections.isEmpty()){
            creatConnections();
        }
        Connection connection = connections.remove(0);
        return connection;
    }

    public void addBack(Connection connection){
        connections.add(connection);
    }
}

存在的问题

  • 自己定义了归还连接的方法addBack。维护困难

五,自定义连接池优化版
解决问题思路
一般开发都能记住Connection类中close方法
将该close方法功能改变为归还连接
中间类ConnectionWrapper,专注于非close方法的调用

package t1.example.util;

/*
        public : 任何地方都能访问
        protected : 只在子父类关系中
        默认 : 同包
        private : 本类
     */

import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * 中间类
 * 处理其他方法
 * 使用普通Connection调用一次
 */
public  class ConnectionWrapper implements Connection {



    //protected:只能在子父类进行访问
    protected Connection connection;

    public ConnectionWrapper() {
    }

    public ConnectionWrapper(Connection connection) {
        this.connection = connection;
    }

    @Override
    public Statement createStatement() throws SQLException {
        return connection.createStatement();
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }
   //...
   
}

package t1.example.util;

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

public class MyConnectionWrapper extends ConnectionWrapper {

    //声明被代理类引用
    private List<Connection> connectionList;

    public MyConnectionWrapper(Connection connection, List<Connection> connectionList) {
        super(connection);
        this.connectionList = connectionList;
    }

    @Override
    public void close() throws SQLException {
        //增强closa:归还连接
        //把Connection归还给连接池
        connectionList.add(connection);
    }
    
}

存在的问题:必须要重写接口中的所有方法

六,自定义连接池的终极版

package t1.example.util;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.LinkedList;

/**
 * 自定义连接池终极版
 */
public class MyDataSource {

    int initPoolSize = 3;
    LinkedList<Connection> connections = new LinkedList<>();

    public MyDataSource(){
        createConnections();
    }

    public void createConnections(){
        for (int i = 1 ; i <= initPoolSize ; i++) {
            try {
                Connection connection = JDBCUtils.getConnection();
                connections.add(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 取出连接
     * @return
     */
    public Connection getConnection(){
        //连接池中的连接够用
        if (connections.size() == 0 || connections.isEmpty()) {
            //连接池中的连接不够用 , 新建一些连接存储连接池中
            createConnections();
        }
        Connection connection = connections.remove(0);//普通连接对象
        //根据普通连接对象 获取 一个连接代理对象(增强连接对象)
        Connection connectionProxy = (Connection) Proxy.newProxyInstance(
                connection.getClass().getClassLoader(),
                connection.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //处理增强close方法
                        String methodName = method.getName();
                        Object returnValue = null;
                        if ("close".equals(methodName)) {
                            //如果是close方法,归还连接
                            returnValue = connections.add(connection);
                        } else {
                            //如果不是close方法,就执行原有功能
                            returnValue = method.invoke(connection, args);
                        }
                        return returnValue;
                    }
                });
        return connectionProxy;
    }

    /**
     * 归还连接
     * @param connection
     */
//    public void addBack(Connection connection){
//        connections.add(connection);
//    }


}

使用动态代理方式解决装饰者设计模式中的弊端:必须要重写接口中的所有方法

7,Java内置注解
概念:就是一个修饰符

特点: 是JDK5.0之后引入的特性。以“@注解名”形式存在

作用:
跟踪代码依赖性
执行编译时格式检查
代替已有的配置文件
@Overirde:标记指定方法是一个重写方法,否则报错
@Deprecated:标记一个类、字段、方法是一个过时的!
@SuppressWarings:压制警告

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

value : 注解所压制的警告的类型
unchecked 未检查的转化,如集合没有指定类型还添加元素
unused 未使用的变量
resource 有泛型未指定类型
path 在类路径,原文件路径中有不存在的路径
deprecation 使用了某些不赞成使用的类和方法
fallthrough switch语句执行到底没有break关键字
rawtypes 没有写泛型,比如: List list = new ArrayList();
all 全部类型的警告(用的最多的)

8,注解分类
标记注解
注解中没有属性
比如:@Override、@Deprecated
单值注解
注解中只有一个属性(属性为value时可以不写value)
比如:@SuppressWarings
完整注解
注解中有多个属性

10,自定义注解
格式:

public @interface 注解名 {
    数据类型 属性名1() default 默认值1;
    数据类型 属性名2() ;
    //没有默认值,在使用时必须要给属性赋值,有默认值依然可以重新赋值
    //通过案例可知只有单独使用value命名的属性时可以省略
}

11,元注解概述
概述:作用在自定义注解上,规定自定义注解的作用区域、存活策略(生命周期)!
常用的元注解:
@Target:规定自定义注解的作用区域
TYPE:类、接口、注解、枚举
FIELD:成员你变量
METHOD:成员方法
PARAMETER:形参
CONSTRUCTOR:构造器
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型
PACKAGE:包

@Retention:规定自定义注解的存活策略
SOURCE : 仅存活在源码
CLASS : 存活在编译期
RUNTIME : 存活在运行时

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值