单例设计模式&动态代理

1.单例设计模型
  • 作用:确保一个类只有一个对象。
  • 场景:计算机中的回收站、任务管理器、Java中的Runtime类等

饿汉式(提前创建对象)
    把类的构造器私有(保证别人不能new)
    在类中自己创建一个对象,并赋值到一个变量
    定义一个静态方法,返回自己创建的这个对象

public class Demo {
    public static void main(String[] args) {
        // 创建对象
        new Thread(() -> {
            User user = User.getUser();
            System.out.println(Thread.currentThread().getName() + "-->" + user);
        }, "t1").start();

         new Thread(()->{
        User user = User.getUser();
        System.out.println(Thread.currentThread().getName() + "-->" + user);
    },"t2").start();
}
}

class User{
    private String name;
    private Integer age;
    private static User user = new User();
    private User(){
    }
    public static User getUser(){
        return user;
    }
}
  • 懒汉式(第一次获取时创建对象)
        把类的构造器私有(保证别人不能new)
        在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)
        提供一个类方法,在方法中创建并返回对象(要保证只创建一次)

  • 注意
        获取方法需要使用synchronized修饰,以保证只有一个线程可以成功创建出对象

public class Demo {
    public static void main(String[] args) {
        // 单线程
//        Teacher teacher1 = Teacher.getTeacher();
//        System.out.println(teacher1);
//        Teacher teacher2 = Teacher.getTeacher();
//        System.out.println(teacher2);

        //多线程,不能保证返回的是同一个对象(可以加锁解决该问题)

        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Teacher teacher1 = Teacher.getTeacher();
                    System.out.println(Thread.currentThread().getName()+":"+teacher1);
                }
            }).start();
        }
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                Teacher teacher1 = Teacher.getTeacher();
//                System.out.println(Thread.currentThread().getName()+":"+teacher1);
//            }
//        },"t1").start();
//
//        new Thread(new Runnable(){
//            @Override
//            public void run() {
//                Teacher teacher2 = Teacher.getTeacher();
//                System.out.println(Thread.currentThread().getName()+":"+teacher2);
//            }
//        },"t2").start();



    }

}
class Teacher{
    private String name;
    private Integer age;
    //1. 私有化构造器
    private Teacher(){
    }

    //2. 定义一个类变量,用于存储对象
    private static Teacher teacher;

    //3. 定义一个静态方法,返回当前类的对象
    //3.1 同步方法
    public static synchronized Teacher getTeacher(){
        if(teacher==null){
            teacher = new Teacher();
        }
        return teacher;
    }
//    //3.2 同步代码块
//    public static Teacher getTeacher(){
//        if (teacher == null) {
//            synchronized (Teacher.class) {
//                if (teacher == null) {
//                    teacher = new Teacher();
//                }
//            }
//        }
//        return teacher;
//    }


}
  • 枚举实现单例
        直接在枚举中提供一个枚举项就可以实现单例

  • 注意
        Google首席Java架构师、(Effective Java》 一书作者Java集合框架的开创者Joshua Bloch在Effective Java一书中提到
            单元素的枚举类型,已经成为实现singleton的最佳方法
            在这种实现方式中,既可以避免多线程同步问题
            还可以防止通过反射和反序列化来重新创建新的对象
            在很多优秀的开源代码中,我们经常可以看到使用枚举方式来实现的单例模式类

 2.动态代理

java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

public class ProxyUtil {
    public static Star createProxy(Star star){
        //获取被代理对象,参数中已经传入
        //编写代理类的业务逻辑
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //调用代理对象的方法名字
                String methodName = method.getName();
                if(methodName.equals("sing")){
                    //执行代理唱歌方法
                    System.out.println("经纪人—准备话筒,收钱");
                }else{
                    //执行代理跳舞
                    System.out.println("经纪人—准备场地,收钱");
                }
                Object obj = method.invoke(star, args);
                return obj;
            }
        };
        //生成代理对象
        Object obj = Proxy.newProxyInstance(
                star.getClass().getClassLoader(),
                star.getClass().getInterfaces(),
                invocationHandler);
        //返回代理对象返回
        return (Star)obj;


    }
}


public class ProxyUtilTest {
    public static void main(String[] args) {
       //创建被代理对象
        Ycy ycy = new Ycy();
        //生成代理对象
        Star star = ProxyUtil.createProxy(ycy);
        //调用代理对象,让被代理对象干活
        star.sing("ababbaba");
        star.dance();
    }

}



public interface Star {
   String sing(String name);
    void dance();
}


public class Ycy implements Star{

    @Override
    public String sing(String name) {
        System.out.println("Ycy开始唱歌,歌名:"+name);
        return name;
    }

    @Override
    public void dance() {
        System.out.println("Ycy开始跳舞");
    }
}

 案例


/**
 * 目标:使用动态代理解决实际问题,并掌握使用代理的好处。
 */
public class Test {
    public static void main(String[] args) throws Exception{
        // 1、创建用户业务对象
        UserService userService = new UserServiceImpl();

        // 2、调用用户业务的功能。
        userService.login("admin", "123456");
        System.out.println("----------------------------------");

        userService.deleteUsers();
        System.out.println("----------------------------------");

        String[] names = userService.selectUsers();
        System.out.println("查询到的用户是:" + Arrays.toString(names));
        System.out.println("----------------------------------");

    }
}

/**
 * 用户业务接口
 */
public interface UserService {
    // 登录功能
    void login(String loginName, String passWord) throws Exception;

    // 删除用户
    void deleteUsers() throws Exception;

    // 查询用户,返回数组的形式。
    String[] selectUsers() throws Exception;
}


 

/**
 * 用户业务实现类
 */
public class UserServiceImpl implements UserService {
    @Override
    public void login(String loginName, String passWord) throws Exception {
        long time1 = System.currentTimeMillis();
        if ("admin".equals(loginName) && "123456".equals(passWord)) {
            System.out.println("您登录成功,欢迎光临本系统~");
        } else {
            System.out.println("您登录失败,用户名或密码错误~");
        }
        Thread.sleep(1000);
        long time2 = System.currentTimeMillis();
        System.out.println("login方法耗时:" + (time2 - time1));
    }

    @Override
    public void deleteUsers() throws Exception {
        long time1 = System.currentTimeMillis();
        System.out.println("成功删除了1万个用户~");
        Thread.sleep(1500);
        long time2 = System.currentTimeMillis();
        System.out.println("deleteUsers方法耗时:" + (time2 - time1));
    }

    @Override
    public String[] selectUsers() throws Exception {
        long time1 = System.currentTimeMillis();
        System.out.println("查询出了3个用户");
        String[] names = {"张全蛋", "李二狗", "牛爱花"};
        Thread.sleep(500);
        long time2 = System.currentTimeMillis();
        System.out.println("selectUsers方法耗时:" + (time2 - time1));
        return names;
    }
}


public class UserServiceProxyUtil {
    /**
     * 生成代理对象
     * @param userService
     * @return
     */
    public UserService creatProxy(UserService userService) {
        //1.获取被代理对象,就是userService
        //2.创建代理的业务逻辑
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //调用代理对象的方法名字
                String methodName = method.getName();
                if(methodName.equals("login")){
                    System.out.println( new Date() + "--" + Arrays.toString(args) + "登录了");
                }
                //进行计时 开始
                long begin = System.currentTimeMillis();
                //调用真正的方法
                Object obj = method.invoke(userService,args);
                //进行计时,结束
                long end = System.currentTimeMillis();
                //计算插值
                long time = end - begin;
                System.out.println("【"+methodName+"】方法,执行了:【"+time+"毫秒】");
                return obj;
            }
        };
        //3.调用Proxy的API,生成代理对象
        UserService userService1 = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler
        );

        //4.返回代理对象
        return userService1;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值